Qt实现客户端与服务器消息发送

这篇具有很好参考价值的文章主要介绍了Qt实现客户端与服务器消息发送。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

里用Qt来简单设计实现一个场景,即:

(1)两端:服务器QtServer和客户端QtClient

(2)功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度。

环境:VS20013 + Qt5.11.2 + Qt设计师

先看效果:

Qt实现客户端与服务器消息发送

一、基本概念

客户端与服务器的基本概念不说了,关于TCP通信的三次握手等等,在《计算机网络》里都有详细介绍。这里说下两者是如何建立起通信连接的。

(1)IP地址:首先服务器和每一个客户端都有一个地址,即IP地址。(底层的MAC地址,不关心,因为TCP通信以及IP,是七层架构里面的网络层、传输层了,底层透明)。对于服务器来说,客户端的数量及地址是未知的,除非建立了连接。但是对于客户端来说,必须知道服务器的地址,因为两者之间的连接是由客户端主动发起的。

(1)端口号:软件层面的端口号,指的是 “应用层的各种协议进程与运输实体进行层间交互的一种地址”。简而言之,每一个TCP连接都是一个进程,操作系统需要为每个进程分配一个协议端口(即每一个客户端与服务端的连接,不是两台主机的连接,而是两个端口的连接)。但一台主机通常会有很多服务,很多进程,单靠一个IP地址不能标识某个具体的进程或者连接。所以用端口号来标识访问的目标服务器以及服务器的目标服务类型。端口号也有分类,但这不是本文的重点,详见教材。

(3)TCP连接:总的来说,TCP的连接管理分为单个阶段:建立连接 -> 数据传送 -> 连接释放。在(2)里说到,每个TCP连接的是具体IP地址的主机的两个端口,即TCP连接的两个端点由IP地址和端口号组成,这即是套接字(socket)的概念:套接字socket = IP + 端口号。

因此,我们要通过通过套接字来建立服务端与客户端的通信连接。

二、Qt相关类

QTcpSocket:提供套接字

QTcpServer:提供基于TCP的服务端,看官方文档的解释如下:

This class makes it possible to accept incoming TCP connections. You can specify the port or have QTcpServer pick one automatically. You can listen on a specific address or on all the machine’s addresses.

这个解释里面提到两点:

(1)指定端口:即开通哪一个端口用于建立TCP连接;

(2)监听:监听(1)中指定的端口是否有连接的请求。

三、写服务器和客户端的具体流程

(1)服务器:

  1. 创建并初始化 QTcpServer 对象;

  1. 启动服务器监听,通过调用成员函数 listen(QHostAddress::Any, 端口号);

  1. 连接 QTcpServer 对象的 newConnection 信号槽,当有客户端链接时,客户端会发送 newConnection 信号给服务器,触发槽函数接受链接(得到一个与客户端通信的套接字 QTcpSocket);

  1. QTcpsocket 对象调用成员函数 write,发送数据给客户端;

  1. 当客户端有数据发送来,QTcpSocket 对象就会发送 readyRead 信号,关联槽函数读取数据;

  1. 连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发 QTcpsocket 对象的 disconnected 信号,进而触发槽函数进行相应处理。

(2)客户端:

  1. 创建并初始化 QTcpSocket 对象;

  1. QTcpSocket 调用 connectToHost(QHostAddress("IP"), 端口号),连接服务器IP和端口号;

  1. QTcpsocket 对象调用成员函数 write,发送数据给服务器;

  1. 连接QTcpsocket 对象的 connected() 信号槽,当客服端成功连接到服务器后触发 connected() 信号;

  1. 连接QTcpsocket 对象的 readyread() 信号槽,当客户端接收到服务端发来数据时触发 readyread() 信号;

  1. 连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发 QTcpsocket 对象的 disconnected 信号,进而触发槽函数进行相应处理。

四、UI设计

客户端:

Qt实现客户端与服务器消息发送

服务端:

Qt实现客户端与服务器消息发送

五、服务端实现

我们先要在工程文件中加入network

QT       += core gui network

下面我们来看看服务器程序步骤:

1、初始化 QTcpServer 对象

TCP_server = new QTcpServer();

2、启动服务器监听

TCP_server->listen(QHostAddress::Any,9988);//9988为端口号

3、连接 QTcpServer 对象的 newConnection 信号槽,当有客户端链接时,客户端会发送 newConnection 信号给服务器,触发槽函数接受链接(得到一个与客户端通信的套接字 QTcpSocket)

connect(TCP_server, SIGNAL(newConnection()), this, SLOT(slot_newconnect()));

// 在与 newConnection 信号连接的槽函数中,获取与相应客户端通信的套接字
TCP_connectSocket = mServer->nextPendingConnection();

4、QTcpsocket 对象调用成员函数 write,发送数据给客户端

TCP_connectSocket->write(msg.toUtf8());

5、当客户端有数据发送来,QTcpSocket 对象就会发送 readyRead 信号,关联槽函数读取数据

connect(mSocket,SIGNAL(readyRead()),this,SLOT(slot_recvmessage()));

6、连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发 QTcpsocket 对象的 disconnected 信号,进而触发槽函数进行相应处理

connect(mSocket,SIGNAL(disconnected()),this,SLOT(slot_disconnect()));

TCP_Server.h

#ifndef TCP_SERVER_H
#define TCP_SERVER_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>

namespace Ui {
class TCP_Server;
}

class TCP_Server : public QWidget
{
    Q_OBJECT

public:
    explicit TCP_Server(QWidget *parent = nullptr);
    ~TCP_Server();

private slots:
    void slot_newconnect(); //建立新连接的槽
    void slot_sendmessage(); //发送消息的槽
    void slot_recvmessage(); //接收消息的槽
    void slot_disconnect(); //取消连接的槽

private:
    Ui::m_tcpServer *ui;

    QTcpServer *TCP_server; //QTcpServer服务器
    QTcpSocket *TCP_connectSocket; //与客户端连接套接字
};

#endif // TCP_SERVER_H

TCP_Server.cpp

#include "tcp_server.h"
#include "ui_tcp_server.h"
#include <QMessageBox>
#include <QDateTime>

TCP_Server::TCP_Server(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TCP_Server)
{
    ui->setupUi(this);

    //初始化
    TCP_server = new QTcpServer();
    TCP_connectSocket = nullptr;
    connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(slot_sendmessage()));

    //调用listen函数监听同时绑定IP和端口号
    if(TCP_server->listen(QHostAddress::LocalHost,10000)) //判断listen是否成功,成功则继续执行,连接新接收信号槽
    {
        this->connect(TCP_server,SIGNAL(newConnection()),this,SLOT(slot_newconnect()));  //将服务器的新连接信号连接到接收新连接的槽
    }
    else
    {
        QMessageBox::critical(this,"错误","IP绑定错误,请关闭其它服务端或更改绑定端口号");
    }
}

TCP_Server::~TCP_Server()
{
    delete ui;
}

//建立新连接的槽
void TCP_Server::slot_newconnect()
{
    if(TCP_server->hasPendingConnections())  //查询是否有新连接
    {
        TCP_connectSocket = TCP_server->nextPendingConnection(); //获取与真实客户端相连的客户端套接字
        ui->textBrowser->append("client login!"); //若有新连接,则提示

        this->connect(TCP_connectSocket,SIGNAL(readyRead()),this,SLOT(slot_recvmessage())); //连接客户端的套接字的有新消息信号到接收消息的槽
        this->connect(TCP_connectSocket,SIGNAL(disconnected()),this,SLOT(slot_disconnect())); //连接客户端的套接字取消连接信号到取消连接槽
    }
}

//发送消息的槽
void TCP_Server::slot_sendmessage()
{
    QString sendMessage = ui->lineEdit->text(); //获取单行文本框内要发送的内容
    if(TCP_connectSocket != nullptr && !sendMessage.isEmpty()) //确保有客户端连接,并且发送内容不为空
    {
        TCP_connectSocket->write(sendMessage.toLatin1());   //发送消息到客户端

        QString localDispalyMessage = "send to client: " + sendMessage \
                        + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss") + tr("\n");
        ui->textBrowser->append(localDispalyMessage);   //将要发送的内容显示在listwidget
    }

    ui->lineEdit->clear();
}

//接收消息的槽
void TCP_Server::slot_recvmessage()
{
    if(TCP_connectSocket != nullptr) //与客户端连接的socket,不是nullptr,则说明有客户端存在
    {
        QByteArray array = TCP_connectSocket->readAll();    //接收消息
        QHostAddress clientaddr = TCP_connectSocket->peerAddress(); //获得IP
        int port = TCP_connectSocket->peerPort();   //获得端口号

        QDateTime datetime = QDateTime::currentDateTime();

        QString sendMessage = tr("recv from :") + clientaddr.toString() + tr(" : ") \
                                + QString::number(port) + tr("   ") + datetime.toString("yyyy-M-dd hh:mm:ss") + tr("\n");
        sendMessage += array;

        ui->textBrowser->append(sendMessage);   //将接收到的内容加入到listwidget
    }
}

//取消连接的槽
void TCP_Server::slot_disconnect()
{
    if(TCP_connectSocket != nullptr)
    {
        ui->textBrowser->append("client logout!");
        TCP_connectSocket->close(); //关闭客户端
        TCP_connectSocket->deleteLater();
    }
}

六、客户端实现

下面我们来看看客户端程序步骤:

1、初始化 QTcpSocket 对象

TCP_server = new QTcpSocket();

2、QTcpSocket 调用 connectToHost(QHostAddress("IP"), 端口号),连接服务器IP和端口号

TCP_sendMesSocket->connectToHost("127.0.0.1",10000); 

3、QTcpsocket 对象调用成员函数 write,发送数据给服务器

//取发送信息编辑框内容
QString msg = ui->sendEdit->toPlainText();
TCP_sendMesSocket->write(msg.toUtf8());//转编码

4、连接QTcpsocket 对象的 connected() 信号槽,当客服端成功连接到服务器后触发 connected() 信号

connect(TCP_sendMesSocket,SIGNAL(connected()),this,SLOT(slot_connected()));

5、连接QTcpsocket 对象的 readyread() 信号槽,当客户端接收到服务端发来数据时触发 readyread() 信号

connect(TCP_sendMesSocket,SIGNAL(readyRead()),this,SLOT(slot_recvmessage()));

6、连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发 QTcpsocket 对象的 disconnected 信号,进而触发槽函数进行相应处理

connect(TCP_sendMesSocket, SIGNAL(disconnected()), this, SLOT(slot_disconnect()));

TCP_Client.h

#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H

#include <QWidget>
#include <QTcpSocket>

namespace Ui {
class TCP_Client;
}

class TCP_Client : public QWidget
{
    Q_OBJECT

public:
    explicit TCP_Client(QWidget *parent = nullptr);
    ~TCP_Client();

//与按钮交互,故函数都设置为槽函数
private slots:
    void slot_connected(); //处理成功连接到服务器的槽
    void slot_sendmessage(); //发送消息到服务器的槽
    void slot_recvmessage(); //接收来自服务器的消息的槽
    void slot_disconnect(); //取消与服务器连接的槽

private:
    Ui::TCP_Client *ui;

    bool isconnetion; //判断是否连接到服务器的标志位
    QTcpSocket *TCP_sendMesSocket; //发送消息套接字
};

#endif // TCP_CLIENT_H

TCP_Client.cpp文章来源地址https://www.toymoban.com/news/detail-505282.html

#include "tcp_client.h"
#include "ui_tcp_client.h"
#include <QHostAddress>
#include <QDateTime>
#include <QMessageBox>

TCP_Client::TCP_Client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TCP_Client)
{
    ui->setupUi(this);

    /***    初始化TCP   ***/
    this->setWindowTitle("TCP客户端");
    this->isconnetion = false;
    //初始化sendMesSocket
    this->TCP_sendMesSocket = new QTcpSocket();

    //终止之前的连接,重置套接字
    TCP_sendMesSocket->abort();
    //给定IP和端口号,连接服务器
    this->TCP_sendMesSocket->connectToHost("127.0.0.1",10000); //QHostAddress::LocalHost等于127.0.0.1,所以两者都可以互相替换

    //成功连接服务器的connected()信号连接到slot_connected() (注意:不是connect()信号)
    connect(TCP_sendMesSocket,SIGNAL(connected()),this,SLOT(slot_connected()));
    //发送按钮的clicked()信号连接到slot_sendmessage()
    connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(slot_sendmessage()));
    //有新数据到达时的readyread()信号连接到slot_recvmessage()
    connect(TCP_sendMesSocket,SIGNAL(readyRead()),this,SLOT(slot_recvmessage()));
    //与服务器断开连接的disconnected()信号连接到slot_disconnect()
    connect(TCP_sendMesSocket,SIGNAL(disconnected()),this,SLOT(slot_disconnect()));
}

TCP_Client::~TCP_Client()
{
    delete ui;
}

//处理成功连接到服务器的槽
void TCP_Client::slot_connected()
{
    this->isconnetion = true;
    ui->textBrowser->append(tr("与服务器连接成功:") + QDateTime::currentDateTime().toString("yyyy-M-dd hh:mm:ss"));
}

//发送消息到服务器的槽
void TCP_Client::slot_sendmessage()
{
    if(this->isconnetion)
    {
        QString sendMessage = ui->lineEdit->text(); //从单行文本框获得要发送消息
        if(!sendMessage.isEmpty())
        {
            //发送消息到服务器
            this->TCP_sendMesSocket->write(sendMessage.toLatin1());
            //本地显示发送的消息
            QString localDispalyMessage = tr("send to server: ") + sendMessage \
                                            + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss") + tr("\n");
            ui->textBrowser->append(localDispalyMessage);
        }
        else
            QMessageBox::warning(this,"错误","消息不能为空!",QMessageBox::Ok);
    }
    else
        QMessageBox::warning(this,"错误","未连接到服务器!",QMessageBox::Ok);

    ui->lineEdit->clear();
}

//接收来自服务器的消息的槽
void TCP_Client::slot_recvmessage()
{
    //接收来自服务器的消息
    QByteArray byteArray = this->TCP_sendMesSocket->readAll();
    QString recvMessage = tr("recv from server: ") + byteArray + QDateTime::currentDateTime().toString(" yyyy-M-dd hh:mm:ss") + tr("\n");
    ui->textBrowser->append(recvMessage);
}

//取消与服务器连接的槽
void TCP_Client::slot_disconnect()
{
    QMessageBox::warning(this,"警告","与服务器的连接中断",QMessageBox::Ok);
    //关闭并随后删除socket
    TCP_sendMesSocket->close();
    TCP_sendMesSocket->deleteLater();
}

到了这里,关于Qt实现客户端与服务器消息发送的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MQTT协议-发布消息(服务器向客户端发送)

    发布消息报文组成:https://blog.csdn.net/weixin_46251230/article/details/129414158 在了解了发布信息的PUBLISH报文后,就可以分析出阿里云服务器向本地客户端发送的报文数据了 实验前需要在阿里云创建产品和设备,并创建简单的温度和湿度物模型:https://blog.csdn.net/weixin_46251230/article/de

    2024年02月06日
    浏览(44)
  • Java 构建websocket客户端,构建wss客户端,使用wss连接,并发送数据到服务器端,接收服务器端消息

    Java 构建websocket客户端,构建wss客户端,使用wss连接,并发送数据到服务器端,接收服务器端消息 回调函数处理

    2024年02月13日
    浏览(45)
  • Qt 服务器/客户端TCP通讯

    最近需要用到TCP/IP通讯,这边就先找个简单的例程学习一下。Qt的TCP通讯编程可以使用QtNetwork模块,QtNetwork模块提供的类能够创建基于TCP/IP的客户端与服务端应用程序,一般会使用QTcpSocket、QTcpServer类 网络通信方式主要有两种:TCP与UDP。以下拷贝网络上总结两者之间的区别:

    2023年04月26日
    浏览(57)
  • 20230904 QT客户端服务器搭建聊天室

    Ser Cli

    2024年02月09日
    浏览(31)
  • Qt多线程TCP服务器客户端传输文件

    TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)。 TCP提供可靠交付的服务。通过TCP 连接传送的数据,无差错、不丢失、不

    2024年02月13日
    浏览(41)
  • HTTP介绍 原理 消息结构 客户端请求 服务器响应 HTTP状态码

    HTTP协议 是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(www.world wide web)服务器传输超文本到本地浏览器的传送协议 HTTP 是基于TCP/IP(三次握手,四次挥手)通信协议来传输数据(HTML文件,图片文件,查询结果等) TCP:可靠的,丢包重传 UTP:不可靠的,直播,

    2024年02月05日
    浏览(45)
  • QT下的多线程TCP客户端和服务器

    qt下的QTcpSocket在同一个线程使用时没有问题的,但是如果进行跨线程,很容易出现问题。那么有什么方法可以跨线程进行使用吗? 答案是肯定的:使用QThread的movetothread可以完成扩线程接收。 首先是基于QTcpSocket的类 头文件tcpsocket.h 然后是cpp文件tcpsocket.cpp 再次基础上,创建

    2024年01月17日
    浏览(41)
  • 服务器端使用django websocket,客户端使用uniapp 请问服务端和客户端群组互发消息的代码怎么写的参考笔记

    2023/8/29 19:21:11 服务器端使用django websocket,客户端使用uniapp 请问服务端和客户端群组互发消息的代码怎么写 2023/8/29 19:22:25 在服务器端使用Django WebSocket和客户端使用Uniapp的情况下,以下是代码示例来实现服务器端和客户端之间的群组互发消息。 服务器端代码 (使用Django Chann

    2024年02月11日
    浏览(34)
  • 使用IO多路复用select完成TCP循环服务器接收客户端消息并打印

    服务器       客户端     结果    

    2024年02月12日
    浏览(36)
  • Idea+maven+springboot项目搭建系列--2 整合Rabbitmq完成客户端&服务器端消息收发

    前言:本文通过springBoot -maven 框架,对Rabbitmq 进行整合,完成客户端消息的发送和消费; 1 为什么要使用Rabbitmq: RabbitMQ 是一个可靠的、灵活的、开源的消息中间件,具有以下优点: 异步通信:RabbitMQ 支持异步通信,使得消息发送者和接收者能够异步处理,提高了系统性能和

    2024年02月07日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包