Tcp通信一般分为客户端和服务器端。
对于客户端,Qt提供QTcpSocket类进行处理,客户端主要功能有连接服务器,发送数据,接收数据等。
示例代码:
//创建套接字
QTcpSocket *tcpSocket;
tcpSocket = new QTcpSocket;
//连接信号和处理槽
connect(tcpSocket, &QTcpSocket::connected, [](){ qDebug() << "Connected successfully !"; });
connect(tcpSocket, &QTcpSocket::disconnected, [](){ qDebug() << "Disconnected!"; });
connect(tcpSocket, &QTcpSocket::stateChanged, [](QAbstractSocket::SocketState socketState){ qDebug() << "SocketState changed: " << socketState;
});
connect(tcpSocket, &QTcpSocket::readyRead,this, &MyThread::slotReadData);
//连接服务器
tcpSocket->connectToHost("192.168.2.194", 5002);
//等待连接成功
tcpSocket->waitForConnected(1000);
//发送数据
QString command = "00 01 02 03 04 05 06 07 08";
QByteArray array = QByteArray::fromHex(command.toLatin1());
tcpSocket->write(array);
tcpSocket->waitForBytesWritten();
tcpSocket->flush();
//接收数据
while(tcpSocket->bytesAvailable()>0){
QByteArray datagram;
datagram.resize(tcpSocket->bytesAvailable());
tcpSocket->read(datagram.data(),datagram.size());
QString msg = datagram.data();
contentListWidget->addItem(msg.left(datagram.size()));
}
//断开连接
tcpSocket->disconnectFromHost();
tcpSocket->waitForDisconnected();
对于服务端,Qt提供了QTcpServer类来帮助我们处理。但是一个服务器端对应很多的客户端,为了方便处理,我们一般继承QTcpServer创建Server子类。重写incomingConnection(int socketDescriptor)函数。子类Server中可以添加QList<QTcpSocket*>类型变量,将所有连接到服务器上的客户端存储下来。在构造函数中,需要添加listen进行监听是否有客户端连接。当有连接来的时候,发出信号incomingConnection(int socketDescriptor),在接收到incomingConnection信号的槽函数中对客户端socket进行处理,可以使用多线程进行处理,对每一个客户端采用一个线程处理。
服务端示例代码:
//server.h
#include <QTcpServer>
#include <QObject>
#include "tcpclientsocket.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
Server(QObject *parent = 0,int port = 0);
QList<TcpClientSocket*> tcpClientSocketList;
signals:
void updateServer(QString ,int);
public slots:
void updateClients(QString ,int);
void slotDisconnected(int);
protected:
void incomingConnection(int socketDescriptor);
};
//server.cpp
Server::Server(QObject *parent, int port) : QTcpServer(parent)
{
listen(QHostAddress::Any,port);
}
void Server::incomingConnection(int socketDescriptor){
TcpClientSocket *tcpClientSocket = new TcpClientSocket(this);
connect(tcpClientSocket,&TcpClientSocket::updateClients,this,&Server::updateClients);
connect(tcpClientSocket,&TcpClientSocket::disconnected,this,&Server::slotDisconnected);
tcpClientSocket->setSocketDescriptor(socketDescriptor);
tcpClientSocketList.append(tcpClientSocket);
}
void Server::updateClients(QString msg,int length){
emit updateServer(msg,length);
for(int i=0; i<tcpClientSocketList.size(); i++){
QTcpSocket *item = tcpClientSocketList.at(i);
if(item->write(msg.toLatin1(),length)!=length){
continue;
}
}
}
void Server::slotDisconnected(int descriptor){
for(int i=0; i<tcpClientSocketList.size();i++){
QTcpSocket *item = tcpClientSocketList.at(i);
if(item->socketDescriptor() == descriptor){
tcpClientSocketList.removeAt(i);
return;
}
}
return;
}
对于服务端的QTcpSocket,主要需要处理接收到客户端的信息,并将该信息传递给所有连接该服务器的客户端(根据需求设计)。示例代码如下:
//tcpclientsocket.h
#include <QTcpSocket>
#include <QObject>
class TcpClientSocket : public QTcpSocket
{
Q_OBJECT
public:
TcpClientSocket(QObject *parent = 0);
signals:
void updateClients(QString, int);
void disconnected(int);
protected slots:
void dataReceived();
void slotDisconnected();
};
//tcpclientsocket.cpp
TcpClientSocket::TcpClientSocket(QObject *parent)
{
connect(this,&QTcpSocket::readyRead,this,&TcpClientSocket::dataReceived);
connect(this,&TcpClientSocket::disconnected,this,&TcpClientSocket::slotDisconnected);
}
void TcpClientSocket::dataReceived(){
while(bytesAvailable()>0){
int length = bytesAvailable();
char buf[1024];
read(buf,length);
QString msg = buf;
emit updateClients(msg,length);
}
}
void TcpClientSocket::slotDisconnected(){
emit disconnected(this->socketDescriptor());
}
如果客户端用多线程处理,示例处理代码如下:
//调用
WorkerThread* thread = new WorkerThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));thread->start();
//run()函数
QTcpSocket tcpSocket;
if(!tcpSocket.setSocketDescriptor(socketDesc)) return;
QString info = QString("[%0:%1]").arg(tcpSocket.peerAddress().toString()).arg(tcpSocket.peerPort());
qDebug() << info << " connected.";
while (true){
if(tcpSocket.error() == QAbstractSocket::RemoteHostClosedError)
break;
if(tcpSocket.waitForReadyRead(0))
{
QByteArray data = tcpSocket.readAll();
if(strncmp(data.toStdString().c_str(), "quit", 4) == 0)
break;
tcpSocket.write(data);
tcpSocket.waitForBytesWritten();
}
}
tcpSocket.close();
qDebug() << info << " disconnected.";