服务器端
服务器端通讯用到的对象是QTcpServer和QTcpSocket。
QTcpServer提供了一个基于TCP的服务器,允许接受传入的TCP连接。可以指定端口,也可以让QTcpServer自动选择一个端口。可以监听特定地址或所有机器地址。
首先调用listen()让服务器侦听传入的连接。每次客户端连接到服务器时,都会发出newConnection()信号。然后再调用nextPendingConnection()以接受挂起的连接作为已连接的QTcpSocket。
TCPServer.h
#ifndef TCPSERVER_H #define TCPSERVER_H #include <QObject> #include <QTcpServer> #include <QTcpSocket> #include <QTimer> class TCPServer : public QObject { Q_OBJECT public: explicit TCPServer(QObject *parent = nullptr); ~TCPServer(); void Start(quint32 port); signals: void SendData(QByteArray data); public slots: //有新客户端连接时触发的槽函数 void OnNewCommunication(); //有新客户端断开时触发的槽函数 void OnDisconnected(); //接收到数据时触发的槽函数 void OnReadyRead(); //发送数据槽函数 void OnSendData(QByteArray data); //定时器槽函数,定时向客户端发送数据 void OnTimeOut(); private: void Close(); QTcpServer* m_pTcpServer; //连接的客户端集合 QVector<QTcpSocket*> m_vecTcpSockets; //方便定时向客户端发送消息 QTimer* m_timer; }; #endif // TCPSERVER_HTCPServer.cpp
#include "TCPServer.h" #include <QDateTime> #include <QDebug> TCPServer::TCPServer(QObject *parent) : QObject(parent) { m_pTcpServer = new QTcpServer(this); //有客户端连接时触发 connect(m_pTcpServer,SIGNAL(newConnection()),this,SLOT(OnNewCommunication())); connect(this,SIGNAL(SendData(QByteArray)),this,SLOT(OnSendData(QByteArray))); m_timer = new QTimer(); m_timer->setInterval(5000); connect(m_timer,SIGNAL(timeout()),this,SLOT(OnTimeOut())); } TCPServer::~TCPServer() { Close(); delete m_pTcpServer; delete m_timer; } void TCPServer::Start(quint32 port) { m_pTcpServer->listen(QHostAddress::Any,port); qDebug()<<"[服务器]服务器已启动,监听端口:"<<port; m_timer->start(); } void TCPServer::OnNewCommunication() { //获取新的连接TcpSocket QTcpSocket* pSocket = m_pTcpServer->nextPendingConnection(); m_vecTcpSockets.push_back(pSocket); //有客户端断开连接时触发 connect(pSocket,SIGNAL(disconnected()),this,SLOT(OnDisconnected())); //接收数据时触发 connect(pSocket,SIGNAL(readyRead()),this,SLOT(OnReadyRead())); qDebug()<<"[服务器]客户端:["<<pSocket->peerAddress().toString()<<"::"<<pSocket->peerPort()<<"]已连接......"; } void TCPServer::OnDisconnected() { QTcpSocket* pSocket = qobject_cast<QTcpSocket*>(sender()); m_vecTcpSockets.removeOne(pSocket); qDebug()<<"[服务器]客户端:["<<pSocket->peerAddress().toString()<<"::"<<pSocket->peerPort()<<"]断开连接......"; pSocket->deleteLater(); } void TCPServer::OnReadyRead() { QTcpSocket* pSocket = qobject_cast<QTcpSocket*>(sender()); if(pSocket->bytesAvailable() <= 0) return; QByteArray arr = pSocket->readAll(); qDebug()<<"[服务器]接收到客户端["<<pSocket->peerAddress().toString()<<"::"<< pSocket->peerPort() <<"]的数据:"<<arr; } void TCPServer::OnSendData(QByteArray data) { foreach (QTcpSocket* pSocket, m_vecTcpSockets) { pSocket->write(data); qDebug()<<"[服务器]向客户端["<<pSocket->peerAddress().toString()<<"::"<< pSocket->peerPort() <<"]发送数据:"<<data; } } void TCPServer::OnTimeOut() { QString context = "["+QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") + "]: Hello,Client!"; QByteArray bytes; bytes.append(context); emit SendData(bytes); } void TCPServer::Close() { foreach (QTcpSocket* pSocket, m_vecTcpSockets) { pSocket->close(); pSocket->deleteLater(); } m_vecTcpSockets.clear(); if(m_pTcpServer->isListening()) { m_pTcpServer->close(); } }main.cpp
#include "TCPServer.h" #include <QCoreApplication> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TCPServer pTcpServer; pTcpServer.Start(8888); return a.exec(); }客户端
客户端只需要使用QTcpSocket。
QTcpSocket提供了一个TCP套接字,允许您建立TCP连接和传输数据流。
首先调用connectToHost连接服务器,会发送一个connected()信号。然后通过read()和write()可以接受和写入需要传输的数据。
TCPClient.h
#ifndef TCPCLIENT_H #define TCPCLIENT_H #include <QObject> #include <QTcpSocket> #include <QTimer> class TCPClient : public QObject { Q_OBJECT public: explicit TCPClient(QObject *parent = nullptr); ~TCPClient(); void Start(QString ip, quint32 port); signals: void SendData(QByteArray data); public slots: void OnConnected(); void OnDisconnected(); void OnSocketReadyRead(); void OnSendData(QByteArray data); //定时器槽函数,定时向服务器发送数据 void OnTimeOut(); private: QTcpSocket *m_tcpSocket; //方便定时向服务器发送消息 QTimer* m_timer; }; #endif // TCPCLIENT_HTCPClient.cpp
#include "TCPClient.h" #include <QDateTime> #include <QHostAddress> TCPClient::TCPClient(QObject *parent) : QObject(parent) { m_tcpSocket = new QTcpSocket(this); connect(m_tcpSocket,SIGNAL(connected()),this,SLOT(OnConnected())); connect(m_tcpSocket,SIGNAL(disconnected()),this,SLOT(OnDisconnected())); connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(OnSocketReadyRead())); connect(this,SIGNAL(SendData(QByteArray)),this,SLOT(OnSendData(QByteArray))); m_timer = new QTimer(this); m_timer->setInterval(5000); connect(m_timer,SIGNAL(timeout()),this,SLOT(OnTimeOut())); } TCPClient::~TCPClient() { delete m_tcpSocket; delete m_timer; } void TCPClient::Start(QString ip, quint32 port) { m_tcpSocket->connectToHost(QHostAddress(ip), port); } void TCPClient::OnConnected() { qDebug()<<"[客户端]已连接服务器:"<<m_tcpSocket->peerAddress().toString(); //只有客户端连接上之后才能发消息,要不会报异常 //QNativeSocketEngine::write() was not called in QAbstractSocket::ConnectedState m_timer->start(); } void TCPClient::OnDisconnected() { qDebug()<<"[客户端]已从服务器断开:"<<m_tcpSocket->peerAddress().toString(); m_timer->stop(); } void TCPClient::OnSocketReadyRead() { QByteArray bytes = m_tcpSocket->readAll(); qDebug()<<"[客户端]从服务器接收到数据:"<<bytes; } void TCPClient::OnSendData(QByteArray data) { if(m_tcpSocket->isOpen()) { qDebug()<<"[客户端]向服务器发送数据:"<<data; m_tcpSocket->write(data); } } void TCPClient::OnTimeOut() { if(m_tcpSocket->isOpen()) { QString context = "["+QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") + "]"+ m_tcpSocket->localAddress().toString() +": Hello,Server!"; QByteArray bytes; bytes.append(context); emit SendData(bytes); } }main.cpp
#include "TCPClient.h" #include <QCoreApplication> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TCPClient pTcpClient; pTcpClient.Start("192.168.213.128",8888); return a.exec(); }说明
其中为了可以实现自动互相发送消息,使用了Qt的Timer对象,每5秒客户端向服务器发送消息,同时服务器也会向连接的客户端发送消息。
运行结果: