QT的TCP Socket通信仍然有服务端、客户端之分。服务端通过监听某个端口来监听是否有客户端连接到来,如果有连接到来,则建立新的SOCKET连接;客户端通过IP和PORT连接服务端,当成功建立连接之后,就可进行数据的收发了。需要注意的是,在QT中,QT把SOCKET当成输入输出流来对待的,数据的收发是通过read()和write()来进行的,需要与我们常见的send()与recv()进行区分。
要在QT进行SOCKET通信,需要在 工程名.pro 文件中输入 QT += network
服务端
在服务端,建立SOCKET通信需要用到两个类QTcpServer和QTcpSocket。其中QTcpServer是用来建立QT的Server端对象,QTcpSocket是用来建立SOCKET通信的Socket套接字对象。通信建立流程如下所示。
1.建立QTcpServer类的对象
1 2
   | QTcpServer* mp_TCPServer ; mp_TCPServer = new QTcpServer();
   | 
 
2.监听
QT中,通过listen()建立对端口的监听。使用方式如下:mp_TCPServer->listen(地址类型, 端口号);
1 2 3 4 5 6
   | int port = ui->m_portLineEdit->text().toInt();	 if(!mp_TCPServer->listen(QHostAddress::Any, port)) {      QMessageBox::information(this, "QT网络通信", "服务器端监听失败!");      return; }
   | 
 
其中,QHostAddress定义了集中特殊的IP地址,如
- QHostAddress::Null表示一个空地址;
 
- QHostAddress::LocalHost表示IPv4的本机地址127.0.0.1;
 
- QHostAddress::LocalHostIPv6表示IPv6的本机地址;
 
- QHostAddress::Broadcast表示广播地址255.255.255.255;
 
- QHostAddress::Any表示IPv4的任意地址;
 
- QHostAddress::AnyIPv6表示IPv6的任意地址。
 
3.关联接收连接信号与槽函数
服务端通过信号 SIGNAL:newConnection() 来判断是否接收到了新的连接,当服务端接收到一个客户端的连接时,就会触发信号newConnection(),此时调用相应的槽函数(如自定义函数:ServerNewConnection())保存新接收到的连接;所以需要在服务端监听端口之后建立信号与槽函数的连接。通过connect函数建立联系:
1
   | connect(mp_TCPServer, SIGNAL(newConnection()), this, SLOT(ServerNewConnection()));
   | 
 
在ServerNewConnection()函数中,通过nextPendingConnection()函数获得连接客户端的SOCKET套接字:
1
   | mp_TCPSocket = mp_TCPServer->nextPendingConnection();
   | 
 
4.接收数据
在QT中QT通过信号SIGNAL:readyRead()来判断是否有数据传入,当客户端向服务端成功发送数据之后,就会在服务端触发readyRead()信号,此时通过调用相应的自定义的槽函数(如:ServerReadData())保存接收到的数据;通过connect函数建立信号readyRead()与槽函数ServerReadData()的连接:
1
   | connect(mp_TCPSocket, SIGNAL(readyRead()), this, SLOT(ServerReadData()));
   | 
 
在接收函数ServerReadData()函数中通过read()函数获取数据:
1
   | mp_TCPSocket->read(buffer, 1024);
   | 
 
需要注意的是read()函数有多个重载函数,保存接收数据的数据类型可以是QByteArray也可以是char类型,根据个人习惯或者任务需求选择合适的read()函数。不过,为了保持一致性,建议选择char类型,一是因为数据类型容易识别;二是因为熟悉C\C++语言开发的对char*应该比较熟悉,防止使用上的错误。
5.发送数据
在QT中,通过write函数向外部发送数据:
1 2 3 4 5
   | int sendRe = mp_TCPSocket->write(sendMsgChar, strlen(sendMsgChar)); if( -1 == sendRe) {    QMessageBox::information(this, "QT网络通信", "服务端发送数据失败!"); }
   | 
 
客户端
1.建立QTcpSocket类的对象
建立Socket的套接字:
1 2
   | QTcpSocket* mp_clientSocket; mp_clientSocket = new QTcpSocket();
   | 
 
2.连接服务端
客户端通过connectToHost(IP, Port)函数连接服务端
1
   | mp_clientSocket->connectToHost(ip, port);
   | 
 
3.接收数据
客户端接收数据与服务端接收数据的机制是相同的。通过readyRead()信号是否被触发来判断是否有数据传入,如果该信号被触发,则调用自定义函数(如:ClientRecvData())来保存接收到的数据。通过connect()函数,将信号readyRead()与槽函数ClientRecvData()建立映射关系。
在槽函数ClientRecvData()中通过read()函数接收数据,具体使用方法请参考服务端接收数据。
4.发送数据
客户端发送数据也是通过write()函数来实现,具体使用方法请参考服务端发送数据
实例
服务端示例
1.在sockettcpserver.h中添加具体如下代码:
1 2 3 4 5 6 7 8 9 10 11 12
   | private:     Ui::SocketTCPServer *ui;       QTcpServer *mp_TCPServer;     QTcpSocket *mp_TCPSocket; private slots:       void OnBtnInitSocket();     void OnBtnSendData();     void ServerReadData();     void ServerNewConnection();     void sServerDisConnection();
   | 
 
2.在构造函数中添加如下代码:
1 2 3
   | ui->m_portLineEdit->setText("5550");     connect(ui->m_initSocketBtn, SIGNAL(clicked()), this, SLOT(OnBtnInitSocket()));     connect(ui->m_sendData, SIGNAL(clicked()), this, SLOT(OnBtnSendData()));
  | 
 
3.ServerNewConnection()具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
   |      mp_TCPSocket = mp_TCPServer->nextPendingConnection();     if(!mp_TCPSocket)     {         QMessageBox::information(this, "QT网络通信", "未正确获取客户端连接!");         return;     }     else     {         QMessageBox::information(this, "QT网络通信", "成功接受客户端的连接");         connect(mp_TCPSocket, SIGNAL(readyRead()), this, SLOT(ServerReadData()));         connect(mp_TCPSocket, SIGNAL(disconnected()), this, SLOT(sServerDisConnection()));     }
 
  | 
 
4.ServerReadData()具体实现:
1 2 3 4 5 6 7 8 9 10 11 12
   | char buffer[1024] = {0};     mp_TCPSocket->read(buffer, 1024);     if( strlen(buffer) > 0)     {         QString showNsg = buffer;         ui->m_recvDataTextEdit->append(showNsg);     }     else     {         QMessageBox::information(this, "QT网络通信", "未正确接收数据");         return;     }
  | 
 
5.OnBtnInitSocket()具体实现:
1 2 3 4 5 6 7 8 9 10 11 12
   | mp_TCPServer = new QTcpServer();     int port = ui->m_portLineEdit->text().toInt();     if(!mp_TCPServer->listen(QHostAddress::Any, port))     {         QMessageBox::information(this, "QT网络通信", "服务器端监听失败!");         return;     }     else     {         QMessageBox::information(this, "QT网络通信", "服务器监听成功!");     }     connect(mp_TCPServer, SIGNAL(newConnection()), this, SLOT(ServerNewConnection()));
   | 
 
6.OnBtnSendData()具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | char sendMsgChar[1024] = {0};     QString sendMsg = ui->m_inputTextEdit->toPlainText();     if(sendMsg.isEmpty())     {         QMessageBox::information(this, "QT网络通信", "发送数据为空,请输入数据");         return;     }     strcpy_s(sendMsgChar, sendMsg.toStdString().c_str());     if(mp_TCPSocket->isValid())     {         int sendRe = mp_TCPSocket->write(sendMsgChar, strlen(sendMsgChar));         if( -1 == sendRe)         {             QMessageBox::information(this, "QT网络通信", "服务端发送数据失败!");         }     }     else     {         QMessageBox::information(this, "QT网络通信", "套接字无效!");     }
  | 
 
7.sServerDisConnection()具体实现:
1 2
   | QMessageBox::information(this, "QT网络通信", "与客户端的连接断开");     return;
   | 
 
客户端示例
1.在sockettcpclient.h中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11
   | private slots:     void on_m_connectServerBtn_clicked();       void on_pushButton_2_clicked();       void ClientRecvData();   private:     Ui::SocketTCPClient *ui;       QTcpSocket *mp_clientSocket;
   | 
 
2.在构造函数中添加如下代码:
1 2
   | ui->m_serverIPLineEdit->setText("127.0.0.1");     ui->m_serverPortLineEdit_2->setText("5550");
  | 
 
3.on_m_connectServerBtn_clicked()函数具体实现如下:
1 2 3 4 5 6 7 8 9 10
   | mp_clientSocket = new QTcpSocket();     QString ip = ui->m_serverIPLineEdit->text();\     int port = ui->m_serverPortLineEdit_2->text().toInt();     mp_clientSocket->connectToHost(ip, port);     if(!mp_clientSocket->waitForConnected(30000))     {         QMessageBox::information(this, "QT网络通信", "连接服务端失败!");         return;     }      connect(mp_clientSocket, SIGNAL(readyRead()), this, SLOT(ClientRecvData()));
   | 
 
1 2 3 4 5 6 7 8 9 10
   |     QString sendMsg = ui->m_sendTextEdit->toPlainText();    char sendMsgChar[1024] = {0};    strcpy_s(sendMsgChar, sendMsg.toStdString().c_str());    int sendRe = mp_clientSocket->write(sendMsgChar, strlen(sendMsgChar));    if(sendRe == -1)    {         QMessageBox::information(this, "QT网络通信", "向服务端发送数据失败!");         return;    }
 
  | 
 
5.ClientRecvData()函数具体实现如下:
1 2 3 4 5 6 7 8 9 10
   |      char recvMsg[1024] = {0};     int recvRe = mp_clientSocket->read(recvMsg, 1024);     if(recvRe == -1)     {         QMessageBox::information(this, "QT网络通信", "接收服务端数据失败!");         return;     }     QString showQstr = recvMsg;     ui->m_recvTextEdit_2->setText(showQstr);
 
  | 
 
总结
- 连接服务器
m_tcpSocket->connectToHost(“127.0.0.1”, 9877);
connected = m_tcpSocket->waitForConnected();
只有使用waitForConnected()后,QTcpSocket才真正尝试连接服务器,并返回是否连接的结果。 
- 写数据
m_tcpSocket->write(str.toStdString().c_str(), strlen(str.toStdString().c_str()));
m_tcpSocket->waitForBytesWritten();
当使用waitForBytesWritten()后,QTcpSocket才真正发送数据。
m_tcpSocket->write(str1.toStdString().c_str(), strlen(str1.toStdString().c_str()));
m_tcpSocket->write(str2.toStdString().c_str(), strlen(str2.toStdString().c_str()));
的结果是发送了str1str2 
- 断开与服务器的连接
m_tcpSocket->disconnectFromHost()
m_tcpSocket->waitForDisconnected() 
- 善于使用QTcpSocket的SIGNAL:
connected(),disconnected(),error(QAbstractSocket::SocketError)
配合自定义私有开关变量 bool connected,QTimer可以实现自动重连接等逻辑。 
参考:https://blog.csdn.net/bailang_zhizun/article/details/78327974
总结:https://blog.csdn.net/u011125673/article/details/50474491