qt的socket通信分为阻塞和非阻塞方式
所谓阻塞方式是利用waitfor...()函数,等待socket去完成通信。这种方法使用简单,但是会阻塞当前进程,不能在GUI进程中使用。而非阻塞方式就是利用信号(signals)和槽(slots)函数。这种方式会在时间循环中进行,不会阻塞进程,但是代码稍微复杂一些。
首先先看阻塞的方式
连接到服务器
QTcpSocket socket; socket.connectToHost(serverName, serverPort); if (!socket.waitForConnected(Timeout)) { emit error(socket.error(), socket.errorString()); return; }其中serverName是服务器的IP或者地址,serverPort是服务器的端口号,Timeout是允许延迟,超过此时间则不再等待
接收数据
while (socket.bytesAvailable() < (int)nSize) { if (!socket.waitForReadyRead(Timeout)) { emit error(socket.error(), socket.errorString()); return; } }nSIze是总共要接收的大小,当数据来够时就可以使用socket的read函数读出来了,也可以使用数据流来读出,例如将其读入一个QString中
QDataStream in(&socket); in.setVersion(QDataStream::Qt_5_0); QString example; in >> example;
发送数据,与接收大体相同
QString example = "hello world!"; socket.write(example); if(!socket.waitForBytesWritten(Timeout)) { emit error(socket.error(), socket.errorString()); return; }
再来看非阻塞方式,非阻塞方式使用了信号和槽,来确保信息的收发
QTcpSocket tcpClient; //客户端套接字 connect(&tcpClient,&QTcpSocket::connected,this,&Client::acceptTransfer); //当连接到服务器时出发acceptTransfer connect(ui->pushButton_Start,&QPushButton::Clicked,this,&Client::start); //当点击start按钮时,出发start void Client::start() { tcpClient.connectToHost(serverIP, serverPort); //连接到serverIP的serverPort端口 } void Client::acceptTransfer() { //将来数据的信号与发送接收文件的槽相连 connect(&tcpClient,&QTcpSocket::readyRead,this,&Client::updateClientProgress); connect(&tcpClient, &QTcpSocket::bytesWritten,this, &Client::send_updateClientProgress); }
我们只需要在这两个函数中根据自己拟定的协议完成收发的具体函数就可以了
我们还可以使用如下的连接
connect(&tcpClient,static_cast<void (QAbstractSocket:: *)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),this,&Client::displayError);
服务器端的写法与客户端基本相同,所不同的是要先建立一个QTcpServer的服务器然后再建立QTcpSocket。当有连接来时,会触发newConnection信号
服务器端通过如下语句获取连接
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
如果想要连接多个客户端并发收发,需要对不同的客户端新建线程,具体可参考Qt 助手