最简洁完整的Qt服务器和客户端TCP通讯代码

服务器端

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

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值