服务器端
服务器端通讯用到的对象是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_H
TCPServer.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_H
TCPClient.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秒客户端向服务器发送消息,同时服务器也会向连接的客户端发送消息。
运行结果: