qt tcp通讯

TCP 协议(Transmission Control Protocol)全称是传输控制协议是一种面向连接的、可靠的、

基于字节流的传输层通信协议。

tcp服务端使用QTcpServer、QTcpSocket。

tcp客户端使用QTcpSocket

1.在工程文件(工程文件.pro)中的第一行添加network 如

QT += core gui network //network是添加之后的

2.引用头文件

#include<QTcpServer>//监听套接字

#include<QTcpSocket>//通信套接字

服务端

1.创建QTcpServer对象

2.启动服务器(监听)调用成员方法listen(QHostAddress::Any,端口号)

3.当有客户端连接时候会发送newConnection信号,触发槽函数接受连接(调用 nextPendingConnection函数得到一个与客户端通信的套接字QTcpSocket),通过QTcpSocket对象调用peerAddress、peerPort得到客户端的ip地址和端口。

4.QTcpsocket发送数据用成员方法write

5.读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据。

和客户端建立连接之后用于通信的 QTcpSocket 套接字对象,它是 QTcpServer 的一个子对象,当 QTcpServer 对象析构的时候会自动析构这个子对象,当然也可自己手动析构,建议用完之后自己手动析构这个通信的 QTcpSocket 对象

超时接受连接函数waitForNewConnection

bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR);

msec:指定阻塞的最大时长,单位为毫秒(ms)

timeout:传出参数,如果操作超时 timeout 为 true,没有超时 timeout 为 false

常用信号

  1. 每次有新连接可用时都会发出 newConnection () 信号

  1. 当接受新连接导致错误时,将发射acceptError信号

常用的函数

virtual void disconnectFromHost(); //和对方断开连接

自己调用disconnectFromHost函数,则对方会收到信号void disconnected(),从而实现自己断开连接的处理,如关闭套接字。

onnect(tcpSocket,&QTcpSocket::disconnected,this,[=]()
        {
            //断开连接
            tcpSocket->close();
            tcpSocket->deleteLater();
            emit recvOver();

        });

virtual void incomingConnection(qintptr handle);

当有新的连接可用时,QTcpServer将调用这个虚拟函数。socketDescriptor参数是接受连接的本地套接字描述符。基本实现创建一个QTcpSocket,设置套接字描述符,然后将QTcpSocket存储在一个挂起连接的内部列表中。最后发出newConnection()。所以在服务器上一般说是incomingConnection和newConnection二选一实现。具体分别使用的场景:

  1. 如果服务器只和一个客户端连接,通讯的套接字和监听套接字在同一子线程,使用newConnection。

  1. 如果服务器和多个客户端连接,那需要一个客户端开一个线程,同时通讯套接字在每一个线程创建,把handle传到线程中,并在线程套接字调用setSocketDescriptor函数设置handle。QTcpServer若为每个客户端分配一个独立线程,必须重写incomingConnection()函数。

void someFunction()
{
    //some code
    //need that time cost process(ChatBusiness)
    ChatBusiness *chatBusiness = new chatBusiness();
    QThread *thread = new thread();
    chatBusiness->moveToThread(thread);
    emit chatBusiness->startSignal();//start the thread
}


void MyTcpServer::incomingConnection(qintptr handle)
{
    //create subThreaad
    QThread *thread = new QThread(this);
    ChatBusiness *chatBusiness = new ChatBusiness();
    chatBusiness->moveToThread(thread);
    //def handle of start
    connect(chatBusiness, &ChatBusiness::start, chatBusiness, &ChatBusiness::mainBusiness);
    thread->start();
    //send the SocketDescriptor
    emit chatBusiness->start(handle);
}

void ChatBusiness::mainBusiness(qintptr handle)
{
    QTcpSocket *tcpSocket = new QTcpSocket(this);
    tcpSocket->setSocketDescriptor(handle);
}

QTcpServer类的工作机制是在有传入连接时,QTcpServer会创建一个与客户端匹配的socket,并返回一个指向socket内存的socketDescriptor(socket描述符),在QT中该描述符是qintptr类型的。然后QTcpSer​​​​​​​ver会自动调用incomingConnection()函数,该函数接收这个socketDescriptor。

在incomingConnection()函数的原实现中,创建了一个QTcpSocket对象,然后调用函数QTcpSocket::setSocketDescriptor(qintptr socketDescriptor)设置socket描述符。最后在incomingConnection()函数中又调用了addPendingConnection(QTcpSocket * socket),将创建的QTcpSocket对象指针挂起在已创建列表中,该行为可终止waitForNewConnection()的阻塞,并且用户可以通过调用nextPendingConnection()函数获得这个QTcpSocket对象指针。在线程版的incomingConnection()函数中,可以省略这步addPendingConnection()的调用,因为不再需要通过nextPendingConnection()函数来获得socket指针了。


#ifndef CTCPSERVER_H
#define CTCPSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>

class CTcpServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit CTcpServer(QTcpServer *parent = nullptr);

    //发送信息到已连接的所有客户机
    void sendData(QString data);
signals:
    //通过该信号传递接收到的数据
    void recvDataSignal(QString data);
public slots:
    //当有新连接时的槽函数
    void newClient();
    //当有数据来时的槽函数
    void readyReadData();
private:
    QList<QTcpSocket *> m_clientList;   //存放客户端socket的容器
};

#endif // CTCPSERVER_H

#include "CTcpServer.h"
#include <QTcpServer>

CTcpServer::CTcpServer(QTcpServer *parent) : QTcpServer(parent)
{
    //设置可以连接的ip和端口号(此处为任意ip且端口号为6666的可以连接);若要指定ip,设置第一个参数即可
    this->listen(QHostAddress::Any, 8866);
    //连接相关的信号槽
    connect(this, &CTcpServer::newConnection, this, &CTcpServer::newClient);
}

void CTcpServer::sendData(QString data)
{
    //遍历客户端列表,将数据发送到所有客户端中(类似广播)
    foreach (QTcpSocket *temp, m_clientList)
    {
        temp->write(data.toLocal8Bit(), data.length());
    }
}

void CTcpServer::newClient()
{
    //循环获取客户端socket
    while (this->hasPendingConnections())
    {
        QTcpSocket *clientTemp = this->nextPendingConnection();   //拿到当前的socket
        m_clientList.append(clientTemp);    //将当前socket添加到列表中(方便操作)
        connect(clientTemp, &QTcpSocket::readyRead, this, &CTcpServer::readyReadData);
    }
}

void CTcpServer::readyReadData()
{
    //拿到发送信号的客户端指针,通过该指针读取数据
    QTcpSocket *curClient = dynamic_cast<QTcpSocket *>(sender());
    emit recvDataSignal(curClient->readAll());
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtNetwork>
#include "ctcpserver.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_m_listenButton_clicked();

    void on_m_sendButton_clicked();

    void on_m_closeButton_clicked();

    void on_m_exitButton_clicked();

    void on_appendData(QString data);    //将接收的数据显示

private:
    Ui::MainWindow *ui;

    CTcpServer *m_pserver;
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_pserver(nullptr)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;

    if(m_pserver)
    {
        m_pserver->close();
        delete m_pserver;
        m_pserver = nullptr;
    }

}

void MainWindow::on_m_listenButton_clicked()
{
    m_pserver = new CTcpServer();
    connect(m_pserver, &CTcpServer::recvDataSignal, this, &MainWindow::on_appendData);

}

void MainWindow::on_m_sendButton_clicked()
{
    m_pserver->sendData(ui->m_sendlineEdit->text());

}

void MainWindow::on_m_closeButton_clicked()
{
    if(m_pserver)
    {
        m_pserver->close();
        delete m_pserver;
        m_pserver = nullptr;
    }


}

void MainWindow::on_m_exitButton_clicked()
{


}

void MainWindow::on_appendData(QString data)
{
    ui->m_showtextBrowser->append(data);
}

客户端

1.创建QTcpSocket对象

2.链接服务器connectToHost(QHostAddress("ip"),端口号)

3.QTcpsocket发送数据用成员方法write

4.读数据当对方有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

常用信号

readyRead

如果该类对象发射出 readyRead() 信号,说明对端发送的数据达到了,之后就可以调用 read 函数接收数据了。

connected

调用 connectToHost() 函数连接TCP服务器并成功建立连接之后发出 connected() 信号

disconnected

在套接字断开连接时发出 disconnected() 信号

void error(QAbstractSocket::SocketError);

一般用于调用connectToHost函数后,判断是否连接成功,如果连接不成功,会发射error信号,再通过SocketError error() const;判断是那种错误。

常用的函数

virtual void disconnectFromHost(); //和对方断开连接

自己调用disconnectFromHost函数,则对方会收到信号void disconnected(),从而实现自己断开连接的处理,如关闭套接字。见服务端的代码

SocketError error() const;

disconnectFromHost //断开连接

close //关闭连接




#ifndef CTCPSOCKET_H
#define CTCPSOCKET_H

#include <QObject>
#include <QTcpSocket>

class CTcpSocket : public QTcpSocket
{
    Q_OBJECT
public:
    explicit CTcpSocket(QTcpSocket *parent = nullptr);
    //通过改函数发送数据
    void sendData(QString data);
signals:
    //通过该信号传递接收到的数据
    void recvDataSignal(QString data);
public slots:
    //读取数据的槽函数
    void readyReadData();
};
#endif // CTCPSOCKET_H

#include "CTcpSocket.h"
#include <QHostAddress>

CTcpSocket::CTcpSocket(QTcpSocket *parent) : QTcpSocket(parent)
{
    //连接相应槽函数
    connect(this, &CTcpSocket::readyRead, this, &CTcpSocket::readyReadData);

    //指定ip且端口号为8866, (QHostAddress中指定的ip需本机存在或能连接到才可使用)
    this->connectToHost(QHostAddress("127.0.0.1"), 8866);
}

void CTcpSocket::sendData(QString data)
{
    this->write(data.toUtf8());
}

void CTcpSocket::readyReadData()
{
    emit recvDataSignal(this->readAll());
}

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtNetwork>
#include "ctcpsocket.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_m_connectButton_clicked();

    void on_m_sendButton_clicked();

    void on_m_closeButton_clicked();

    void on_appendData(QString data);    //将接收的数据显示


private:
    Ui::MainWindow *ui;
    CTcpSocket *m_client;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_client(nullptr)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
    if(m_client)
    {
        m_client->close();
        delete m_client;
        m_client = nullptr;
    }
}

void MainWindow::on_m_connectButton_clicked()
{
    m_client = new CTcpSocket;
    connect(m_client, &CTcpSocket::recvDataSignal, this, &MainWindow::on_appendData);

}

void MainWindow::on_m_sendButton_clicked()
{
    m_client->sendData(ui->m_sendlineEdit->text());

}

void MainWindow::on_m_closeButton_clicked()
{
    if(m_client)
    {
        m_client->close();
        delete m_client;
        m_client = nullptr;
    }

}

void MainWindow::on_appendData(QString data)
{
    ui->m_showtextBrowser->append(data);
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT 是一个很强大的跨平台应用程序开发框架,它提供了丰富的网络编程类库,可以很方便地实现 TCP 通讯。下面我们就来看一下 QT 中如何使用 TCP。 首先需要在代码中包含 `QTcpSocket` 和 `QTcpServer` 头文件: ```cpp #include <QTcpSocket> #include <QTcpServer> ``` ## TCP 客户端 TCP 客户端通常需要以下步骤: 1. 创建一个 `QTcpSocket` 对象; 2. 连接到服务器; 3. 发送数据; 4. 接收服务器返回的数据; 5. 断开连接。 下面是一个简单的 TCP 客户端的代码示例: ```cpp #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建 TCP socket 对象 QTcpSocket socket; // 连接到服务器 socket.connectToHost("127.0.0.1", 1234); if (!socket.waitForConnected()) { qDebug() << "Failed to connect to server!"; return -1; } // 发送数据 QByteArray data = "Hello, server!"; socket.write(data); socket.waitForBytesWritten(); // 接收数据 socket.waitForReadyRead(); QByteArray response = socket.readAll(); qDebug() << "Server response:" << response; // 断开连接 socket.close(); return a.exec(); } ``` 上面的代码中,我们首先创建了一个 `QTcpSocket` 对象,然后使用 `connectToHost` 函数连接到服务器。如果连接失败,会输出一条错误信息并退出程序。 接着,我们发送一条消息给服务器,使用 `write` 函数将数据写入 socket 缓冲区,并调用 `waitForBytesWritten` 等待数据发送完成。 然后,我们等待服务器返回数据,使用 `waitForReadyRead` 等待数据可读,并使用 `readAll` 函数将所有可读数据读取出来。 最后,我们关闭 socket 连接。 ## TCP 服务器 TCP 服务器通常需要以下步骤: 1. 创建一个 `QTcpServer` 对象; 2. 绑定服务器地址和端口; 3. 监听客户端连接; 4. 接收客户端数据; 5. 回复客户端数据; 6. 断开连接。 下面是一个简单的 TCP 服务器的代码示例: ```cpp #include <QTcpServer> #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建 TCP server 对象 QTcpServer server; // 绑定服务器地址和端口 if (!server.listen(QHostAddress::Any, 1234)) { qDebug() << "Failed to start server!"; return -1; } qDebug() << "Server started!"; while (server.isListening()) { // 监听客户端连接 QTcpSocket *socket = server.nextPendingConnection(); qDebug() << "New client connected:" << socket->peerAddress().toString(); // 接收客户端数据 socket->waitForReadyRead(); QByteArray data = socket->readAll(); qDebug() << "Received data from client:" << data; // 回复客户端数据 QByteArray response = "Hello, client!"; socket->write(response); socket->waitForBytesWritten(); // 断开连接 socket->close(); } return a.exec(); } ``` 上面的代码中,我们首先创建了一个 `QTcpServer` 对象,并使用 `listen` 函数绑定服务器地址和端口。如果绑定失败,会输出一条错误信息并退出程序。 然后,我们进入一个无限循环,使用 `nextPendingConnection` 函数监听客户端连接。当有新的客户端连接时,会输出一条提示信息,并返回一个 `QTcpSocket` 对象,用于与客户端通讯。 接着,我们使用 `waitForReadyRead` 等待客户端发送数据,并使用 `readAll` 函数读取所有可读数据。 然后,我们回复客户端数据,使用 `write` 函数将数据写入 socket 缓冲区,并调用 `waitForBytesWritten` 等待数据发送完成。 最后,我们关闭 socket 连接。 这就是 QT 中使用 TCP 的基本步骤,希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值