服务器端连接多个客户端,接收客户端信息,返回客户端信息
TcpServer 是在主线程中,重写 incomingConnection函数,每次有新的客户端连接服务器将会自动调用此函数,在此函数中构建新的TcpSocket,并且保存,主线程和子线程通过信号和槽机制通信,使用套接字识别是哪一个socket
多线程机制使用moveTothread,Qt官方更推荐此类方式
class MyTcpSever : public QTcpServer
{
Q_OBJECT
public:
explicit MyTcpSever(QObject* parent = nullptr);
//开启监听
bool startSeverListen(QString sHostPort);
// 当有新连接可用时,QTcpServer将调用此虚拟函数
void incomingConnection(qintptr socketDescriptor) override;
private slots:
//有客户端断开连接
void _clientDisconnected(qintptr socketDescriptor);
private:
// 连接到服务器的客户端链表
QList<MyTcpSocket*> m_tcpClientSocketList;
};
class MyTcpSocket : public QObject
{
Q_OBJECT
public:
MyTcpSocket(qintptr socketDescriptor, QObject* parent = nullptr);
qintptr getSocketDescriptor();
signals:
// 通知服务器 客户端掉线
void clientDisconnect(qintptr socketDescriptor);
private slots:
void _initSocket();
// 处理readyRead信号读取数据
void _receiveData();
// 用来处理客户端断开连接触发disconnected信号
void _clientDisconnected();
private:
QTcpSocket* m_tcpSocket;
QThread* m_thread;
qintptr m_socketDescriptor;
};
MyTcpSever::MyTcpSever(QObject* parent)
{
}
bool MyTcpSever::startSeverListen(QString sHostPort)
{
//监听端口
if (listen(QHostAddress::Any, sHostPort.toInt()))
{
return true;
}
return false;
}
void MyTcpSever::incomingConnection(qintptr socketDescriptor)
{
//只要有新的连接就生成一个新的通信套接字
auto tcpClientSocket = new MyTcpSocket(socketDescriptor, this);
//将这个套接字加入客户端套接字列表中
m_tcpClientSocketList.append(tcpClientSocket);
//处理客户端掉线
connect(tcpClientSocket, &MyTcpSocket::clientDisconnect, this, &MyTcpSever::_clientDisconnected);
}
void MyTcpSever::_clientDisconnected(qintptr socketDescriptor)
{
//如果有客户端断开连接, 就将列表中的套接字删除
for (int i = 0; i < m_tcpClientSocketList.count(); i++)
{
if (m_tcpClientSocketList.value(i)->getSocketDescriptor() == socketDescriptor)
{
m_tcpClientSocketList.removeAt(i);
return;
}
}
}
MyTcpSocket::MyTcpSocket(qintptr socketDescriptor, QObject* parent)
{
qDebug() << u8"主线程" << QThread::currentThread();
m_socketDescriptor = socketDescriptor;
m_thread = new QThread;
this->moveToThread(m_thread);
connect(m_thread, &QThread::started, this, &MyTcpSocket::_initSocket);
m_thread->start();
}
qintptr MyTcpSocket::getSocketDescriptor()
{
return m_socketDescriptor;
}
void MyTcpSocket::_initSocket()
{
//socket放到子线程初始化
m_tcpSocket = new QTcpSocket;
m_tcpSocket->setSocketDescriptor(m_socketDescriptor);
//接收到tcpclientsocket发送过来信息
connect(m_tcpSocket, &QTcpSocket::readyRead, this, &MyTcpSocket::_receiveData);
//客户端断开连接时会触发信号disconnected()
connect(m_tcpSocket, &QTcpSocket::disconnected, this, &MyTcpSocket::_clientDisconnected);
}
void MyTcpSocket::_receiveData()
{
int iPort = m_tcpSocket->peerPort();
qint64 iMaxLength = 1024;
QByteArray baArray = m_tcpSocket->readAll(); //把socket中的消息读出
int i = 0;
while (baArray.length() != 0)
{
QString sMsg = baArray.left(iMaxLength);
baArray = baArray.remove(0, iMaxLength);
i++;
qDebug() << u8"子线程" << QThread::currentThread() << u8"收到:" + sMsg;
m_tcpSocket->write("ok");//服务器向客户端发送指定消息
}
}
void MyTcpSocket::_clientDisconnected()
{
emit clientDisconnect(m_tcpSocket->socketDescriptor());
}
调用的时候只需要
m_tcpServer = new MyTcpSever(this); //创建一个服务器类
m_tcpServer->startSeverListen(需要监听的端口号)