QTcpSocket-Qt使用Tcp通信实现服务端和客户端

版权声明:若无来源注明, Techie亮博客文章均为原创。 转载请以连接形式标明本文标题和地址:
本文标题:QTcpSocket-Qt使用Tcp通信实现服务端和客户端     本文地址: https://www.techieliang.com/2017/12/530/

1. 基本功能

详细说明请见官方文档html

1.1. pro文件配置

使用Qt网络功能须要在pro文件增长网络库服务器

  1. QT += network

1.2. QTcpServer服务端创建

  1. QTcpServer server = new QTcpServer();
  2. connect(server,
  3. &QTcpServer::newConnection,
  4. this,
  5. &MainWindow::server_New_Connect);//监听
  6. if(!server->listen(QHostAddress::Any, 8000)) {
  7. qDebug()<<server->errorString(); //错误信息
  8. }

建立server对象之后首先要监听客户端的链接,经过listen函数能够开启监听,须要指定监听的ip和端口号,ip可以使用QHostAddress::Any网络

QTcpServer当有新客户端链接时会发出QTcpServer::newConnection的信号,只须要关联到自定义的槽便可。app

  1. void MainWindow::server_New_Connect() {
  2. //获取客户端链接
  3. auto socket_temp = server->nextPendingConnection();//根据当前新链接建立一个QTepSocket
  4. m_socket=socket_temp;//记录此链接用于后续数据读写
  5. //链接QTcpSocket的信号槽,以读取新数据
  6. QObject::connect(socket_temp, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
  7. //当断开链接时发出的信号
  8. QObject::connect(socket_temp, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
  9. }

上述为一个新链接到来的槽函数范例,利用nextPendingConnection获取到新链接的socket,存储此socket,并关联对应的信号socket

主要有两个:接收到新数据的信号以及链接断开的信号。函数

当链接断开能够经过响应信号槽机制实现断开后的操做。this

1.3. 客户端创建

客户端为主动链接方,不须要监听,直接创建QTcpSocket便可spa

  1. m_socket = new QTcpSocket;
  2. m_socket->connectToHost("127.0.0.1",80100,QTcpSocket::ReadWrite);
  3. connect(m_socket,SIGNAL(connected()),this,SLOT(connected()));

上述例子使用的是信号槽方式等待链接成功,也可使用阻塞方式:waitForConnected,等到链接成功才会执行后续代码,不须要创建新的槽函数。server

经过connectToHost链接指定ip和端口,同时将socket的链接成功的信号与对应槽链接,当链接成功能够将自定义的标记位置为true,可进行相应的收发。htm

  1. void MainWindow::connected() {
  2. m_is_connected = true;
  3. connect(this->socket,SIGNAL(readyRead()),this,SLOT(readyread())); //链接接收消息槽
  4. QObject::connect(socket_temp,?&QTcpSocket::disconnected,?this,?&MainWindow::socket_Disconnected);//断开链接
  5. }

当链接成功建议将接收和断开链接的信号进行connect

1.4. 消息收发

  • 不阻塞收发:

不管客户端仍是服务端只有在创建链接时有差别,后续的消息收发都相同。

首先经过QTcpSocket::close()能够主动断开链接,不管客户端服务端均可以执行主动断开

经过readyRead()信号能够在接到信息后进行信息操做,在槽中执行QTcpSocket::readAll()能够读取缓冲区全部数据

QTcpSocket::send()可发送信息,调用flush可当即发送缓冲区的数据,不需等待。

  • 阻塞收发:

Qt同时提供了阻塞收发及链接、断开链接的函数:

virtual bool waitForConnected(int msecs = 30000)
virtual bool waitForDisconnected(int msecs = 30000)
virtual bool waitForBytesWritten(int msecs = 30000)
virtual bool waitForReadyRead(int msecs = 30000)

经过上述函数能够实现阻塞链接、断开链接、发送、接收数据内容

2. 其余

2.1. 实现单服务器多客户端通信

网上大部分例子都是单服务器通信,若不作修改链接多个客户端,会出现只有最后一个通信有效的状况。

主要缘由是在监听到新链接时的处理方式不当:

  1. connect(server, &QTcpServer::newConnection, this, &MainWindow::server_New_Connect);//监听
  2. if(!server->listen(QHostAddress::Any, 8000)) {
  3. qDebug()<<server->errorString(); //错误信息
  4. }

注意上述代码在服务端收到信链接时会固定的调用一个槽函数,而槽函数每每写成下述样式:

  1. void MainWindow::server_New_Connect() {
  2. //获取客户端链接
  3. auto socket_temp = server->nextPendingConnection();//根据当前新链接建立一个QTepSocket
  4. m_socket=socket_temp;//记录此链接用于后续数据读写
  5. //链接QTcpSocket的信号槽,以读取新数据
  6. QObject::connect(socket_temp, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
  7. //当断开链接时发出的信号
  8. QObject::connect(socket_temp, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
  9. }

m_socket=socket_temp;//记录此链接用于后续数据读写

这一行等因而每次有一个新的链接都替换了旧的链接记录,天然之友最后一个客户端链接有效,正确的能够创建list存储全部链接的socket,当收发数据时根据须要指定socket进行收发。这时将disconnected信号进行connect就具备了做用,当某个链接断开时应该从全部链接链表中删除此记录。

由nextPendingConnection建立的QTcpSocket,会有QTcpServer维护,当QTcpServer销毁是会自动销毁全部建立的socket,若想提早释放内容能够在disconnected信号发生时主动delete

2.2. 关于QTcpServer

可能考虑到跨平台问题,Qt使用select实现io多路复用,链接数量限制是1024,若须要poll,epoll等可以使用其余库,好比libevent

2.3. 关于数据收发

能够经过setReadBufferSize设置接收缓冲区大小(Qt内部缓冲区大小)

当发送端发送的数据超过buffer大小时会触发readyread信号,须要注意对此状况的处理方法,能够考虑在消息头增长消息长度

未验证:Qt有本身内部的缓冲区,消息发送到系统缓冲区,Qt会读取出来,而调用的Qt函数readall等实际上读取的是Qt内部缓冲区而非系统缓冲区

相关文章
相关标签/搜索