【Qt】基于QTcpSocket的TCP客户端实现

本文档展示了如何使用QTcpSocket类创建一个客户端,详细解释了从创建套接字、连接服务器到发送和接收数据的完整过程。代码包括了ATcpClient类的定义与实现,该类在QThread中运行,支持重连和状态管理,适用于其他项目集成。在main.cpp中进行了简单的测试,向服务器发送数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

客户端通信流程:
①创建套接字:new QTcpSocket。
②连接服务器:可以使用QTcpSocket类的connectToHost()函数来连接服务器。
③向服务器发送或者接受数据。

下面代码一共有三个文件,分别是main.cpp、atcpclient.h、atcpclient.cpp.

其中main.cpp是用于测试ATcpClient的。封装好了的ATcpClient运行于线程中,可用于其他小项目中。

// atcpclient.h

#ifndef ATCPCLIENT_H
#define ATCPCLIENT_H

#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QTimer>

class ATcpClient : public QObject
{
    Q_OBJECT
public:
    ATcpClient(QString sServerIp, int nPort, QObject *parent = 0);
    virtual ~ATcpClient();

    int  sendData(QByteArray baData);
    void setReConnectInterval(int nMSec);

protected:
    virtual void initInThread();
    virtual void deinitInThread();

    virtual void doReConnect();
    virtual void setConnectStatus(bool bIsConnect);

    virtual int doSendDataImp(QByteArray baData);
    virtual int doRecvDataImp(const QByteArray &baRecvData);

signals:
    void sigSendData(QByteArray baData);
    void sigOnDeinit();

private slots:
    void sltSendData(QByteArray baData);
    void sltReadyRead();

    void sltOnConnected();
    void sltOnDisonnected();
    void sltOnError(QAbstractSocket::SocketError nErrCode);
    void sltOnStateChanged(QAbstractSocket::SocketState nSocketState);

private:
    QString m_sServerIp;
    int m_nPort;
    int m_nInterval;
    bool m_bConnected{false};

    QThread* m_pThread{nullptr};
    QTimer* m_pTimer{nullptr};
    QTcpSocket* m_pSocketClient{nullptr};
};

#endif // ATCPCLIENT_H
// atcpclient.cpp

#include "atcpclient.h"
#include <QHostAddress>
#include <QTimer>
#include <QEventLoop>

ATcpClient::ATcpClient(QString sServerIp, int nPort, QObject *parent)
    : m_sServerIp(sServerIp)
    , m_nPort(nPort)
    , m_nInterval(50)
    , QObject(parent)
{
    qDebug() << QString::fromLocal8Bit("ATcpClient::ATcpClient(%1,%2)").arg(m_sServerIp).arg(m_nPort);

    m_pThread = new QThread();
    m_pThread->setObjectName("TcpClient");
    m_pThread->start();
    this->moveToThread(m_pThread);

    //不要直接调用initInThread(),否则并非在线程内初始化
    QTimer::singleShot(0,this, &ATcpClient::initInThread);
}

ATcpClient::~ATcpClient()
{
    qDebug() << "ATcpClient::~ATcpClient()";

    //两种错误的反初始化方法,会导致无法kill掉QTimer.
    //deinitInThread();
    //QTimer::singleShot(0, this, &ATcpClient::deinitInThread);

    //正确的反初始化方法: 在线程内反初始化
    QEventLoop loop;
    connect(this, SIGNAL(sigOnDeinit()), &loop, SLOT(quit()));
    QTimer::singleShot(0, this, &ATcpClient::deinitInThread);
    loop.exec();

    if (nullptr != m_pThread)
    {
        m_pThread->quit();
        m_pThread->wait();
        m_pThread->deleteLater();
    }
}

int ATcpClient::sendData(QByteArray baData)
{
    emit sigSendData(baData);
    return baData.length();
}

void ATcpClient::setReConnectInterval(int nMSec)
{
    m_nInterval = nMSec;
}

void ATcpClient::initInThread()
{
    if(nullptr == m_pTimer)
    {
        m_pTimer = new QTimer(this);
        connect(m_pTimer, &QTimer::timeout, this, &ATcpClient::doReConnect);
    }
    m_pTimer->start(m_nInterval);

    if(nullptr == m_pSocketClient)
    {
        m_pSocketClient = new QTcpSocket(this);
        connect(m_pSocketClient, SIGNAL(connected()), this, SLOT(sltOnConnected()));
        connect(m_pSocketClient, SIGNAL(disconnected()), this, SLOT(sltOnDisonnected()));
        connect(m_pSocketClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(sltOnStateChanged(QAbstractSocket::SocketState)));
        connect(m_pSocketClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sltOnError(QAbstractSocket::SocketError)));
        connect(m_pSocketClient, SIGNAL(readyRead()), this, SLOT(sltReadyRead()));

        m_pSocketClient->setSocketOption(QAbstractSocket::LowDelayOption, 1);// 禁用Nagle算法.
        m_pSocketClient->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
        m_pSocketClient->connectToHost(QHostAddress(m_sServerIp), m_nPort);
    }

    connect(this, SIGNAL(sigSendData(QByteArray)), this, SLOT(sltSendData(QByteArray)));
}

void ATcpClient::deinitInThread()
{
    if(nullptr != m_pTimer)
    {
        m_pTimer->stop();
        delete m_pTimer;
        m_pTimer = nullptr;
    }

    if(nullptr != m_pSocketClient)
    {
	m_pSocketClient->disconnectFromHost();
	delete m_pSocketClient;
	m_pSocketClient = NULL;
    }

    emit sigOnDeinit();
}

void ATcpClient::doReConnect()
{
    if(false == m_bConnected && nullptr != m_pSocketClient)
    {
        m_pSocketClient->disconnectFromHost();
        m_pSocketClient->connectToHost(QHostAddress(m_sServerIp), m_nPort);
    }
}

void ATcpClient::setConnectStatus(bool bIsConnect)
{
    if(m_bConnected != bIsConnect)
    {
        m_bConnected = bIsConnect;
    }
}

int ATcpClient::doSendDataImp(QByteArray baData)
{
    if(nullptr == m_pSocketClient || false == m_bConnected)
    {
        qDebug() << "TcpClient socket not connect.";
        return -1;
    }

    int nWriteSize = m_pSocketClient->write(baData);
    if(m_pSocketClient->flush())
    {
        qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
                 << "] Write["<< nWriteSize
                 <<"]:"<< QString::fromLocal8Bit(baData);
    }
    else
    {
        qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
                 << "] Write Fail["<< nWriteSize
                 << "]:"<< QString::fromLocal8Bit(baData);
    }

    return nWriteSize;
}

int ATcpClient::doRecvDataImp(const QByteArray &baRecvData)
{
    qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
             << "] Recv: " << QString::fromLocal8Bit(baRecvData);
}

void ATcpClient::sltSendData(QByteArray baData)
{
    doSendDataImp(baData);
}

void ATcpClient::sltReadyRead()
{
    QByteArray baRecv = m_pSocketClient->readAll();
    doRecvDataImp(baRecv);
}

void ATcpClient::sltOnConnected()
{
    setConnectStatus(true);
    qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
             <<"] Connect success.";
}

void ATcpClient::sltOnDisonnected()
{
    setConnectStatus(false);
    qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
             << "] Disconnect success.";
}

void ATcpClient::sltOnError(QAbstractSocket::SocketError nErrCode)
{
    qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
             << "] socket error,code:" << nErrCode;
	m_pSocketClient->disconnectFromHost();
    setConnectStatus(false);
}

void ATcpClient::sltOnStateChanged(QAbstractSocket::SocketState nSocketState)
{
    qDebug() << "[" << QString::fromLocal8Bit("%1:%2").arg(m_sServerIp).arg(m_nPort)
             << "] socket state change:" << nSocketState;
}
// main.cpp-用于测试

#include <QCoreApplication>
#include "atcpclient.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    {
        ATcpClient tcpClient("127.0.0.1", 9999);

        for(int i=0; i<5; ++i)
        {
           QThread::sleep(1);
           tcpClient.sendData("aaaa");
        }
    }

    return a.exec();
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值