[QT Programming Series-30]: Multi-process mechanism- QT Socket communication: QTcpSocket, QUdpSocket

Table of contents

Chapter 1 Overview

1.1 Overview

1.2 The essence of QT socket communication

1.3 QUdpSocket related signals

1.4 QTcpSocket related signals

Chapter 2 UDP Communication Example

Server code:

Client code:

Chapter 3 TCP Communication Code Example

Server side code:

Client code:


Chapter 1 Overview

1.1 Overview

In Qt, network communication through sockets (sockets) mainly uses QTcpSocketand QUdpSocketclasses. QTcpSocketIt is used for communication based on TCP protocol, while QUdpSocketit is used for communication based on UDP protocol.

In Qt, network communication using TCP/IP protocol can use QTcpSocketand QTcpServerclass. QTcpServerIt is used to create a server, listen for connection requests and accept client connections, and QTcpSocketis used to create a client and establish a connection with the server.

1.2 The essence of QT socket communication

QUdpSocket和QTcpSocket这两个类,是QT库提供的,应用程序,无论是服务器还是客户端,socket通信本质上就是创建应用程序的类和类对象,并且在socket库提供的QUdpSocket和QTcpSocket类和类对象之间进行对象间通信,当socket对象中有数据时,自动通过信号+槽机制,自动回调应用程序注册到socket对象中的槽函数。这就是QT socket通信的本质。

1.3 QUdpSocket相关的信号

QUdpSocketClass used in Qt for UDP network communication. Here are QUdpSocketsome commonly used signals in:

  1. readyRead(): This signal is triggered when there is new data to be read. Data can be read by callingreadDatagram()methods.

  2. stateChanged(QAbstractSocket::SocketState state): QUdpSocketThis signal is triggered when the state of 's changes. The status can be QAbstractSocket::UnconnectedState(unconnected status), QAbstractSocket::HostLookupState(host lookup status), QAbstractSocket::ConnectingState(connecting status), QAbstractSocket::ConnectedState(connected status), etc.

  3. errorOccurred(QAbstractSocket::SocketError socketError): QUdpSocketThis signal is triggered when an error occurs. socketErrorSpecific error types can be obtained through parameters, such as QAbstractSocket::ConnectionRefusedError(connection refused error), QAbstractSocket::RemoteHostClosedError(remote host closed connection error), etc.

These signals can be connected to related slot functions to achieve corresponding logical processing. An example of use is as follows:

// 声明QUdpSocket对象
QUdpSocket *udpSocket;

// 连接信号和槽函数
connect(udpSocket, &QUdpSocket::readyRead, this, &MyClass::readReady);
connect(udpSocket, &QUdpSocket::stateChanged, this, &MyClass::socketStateChanged);
connect(udpSocket, &QUdpSocket::errorOccurred, this, &MyClass::socketErrorOccurred);

// 槽函数实现
void MyClass::readReady()
{
    QByteArray datagram;
    datagram.resize(udpSocket->pendingDatagramSize());
    QHostAddress senderAddress;
    quint16 senderPort;
    udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
    // 处理读取到的数据
}

void MyClass::socketStateChanged(QAbstractSocket::SocketState state)
{
    // 处理状态变化
}

void MyClass::socketErrorOccurred(QAbstractSocket::SocketError socketError)
{
    // 处理错误
}

By connecting these signals and corresponding slot functions, QUdpSocketthe event response and processing of objects can be realized.

1.4 QTcpSocket相关的信号

In Qt, use the QTcpSocket class for TCP network communication. The following are some common signals of the QTcpSocket class:

  1. connected(): Signal emitted when a TCP socket is successfully connected to a remote host.

  2. disconnected(): Signal emitted when a TCP socket is disconnected from a remote host.

  3. readyRead(): Signal emitted when new data is available for reading. Data can be read by callingread()methods.

  4. bytesWritten(qint64 bytes): A signal sent when a certain number of bytes of data has been successfully written. The number of bytes written can be obtained through the bytes parameter.

  5. hostFound(): The signal emitted when QTcpSocket has successfully found the remote host.

  6. stateChanged(QAbstractSocket::SocketState state): The signal emitted when the state of the QTcpSocket changes. The status can beQAbstractSocket::UnconnectedState(unconnected status),QAbstractSocket::HostLookupState(host lookup status),QAbstractSocket::ConnectingState(connecting status),QAbstractSocket::ConnectedState(connected status), etc.

  7. errorOccurred(QAbstractSocket::SocketError socketError): The signal emitted when an error occurs in QTcpSocket. socketErrorSpecific error types can be obtainedthroughQAbstractSocket::ConnectionRefusedError(connection refused error),QAbstractSocket::RemoteHostClosedError(remote host closed connection error), etc.

These signals can be connected to related slot functions to achieve corresponding logical processing. An example of use is as follows:

// 声明QTcpSocket对象
QTcpSocket *tcpSocket;

// 连接信号和槽函数
connect(tcpSocket, &QTcpSocket::connected, this, &MyClass::socketConnected);
connect(tcpSocket, &QTcpSocket::disconnected, this, &MyClass::socketDisconnected);
connect(tcpSocket, &QTcpSocket::readyRead, this, &MyClass::socketReadyRead);
connect(tcpSocket, &QTcpSocket::bytesWritten, this, &MyClass::bytesWritten);
connect(tcpSocket, &QTcpSocket::hostFound, this, &MyClass::hostFound);
connect(tcpSocket, &QTcpSocket::stateChanged, this, &MyClass::socketStateChanged);
connect(tcpSocket, &QTcpSocket::errorOccurred, this, &MyClass::socketErrorOccurred);

// 槽函数实现
void MyClass::socketConnected()
{
    // 处理连接成功事件
}

void MyClass::socketDisconnected()
{
    // 处理断开连接事件
}

void MyClass::socketReadyRead()
{
    // 处理有数据可读事件
}

void MyClass::bytesWritten(qint64 bytes)
{
    // 处理数据写入事件
}

void MyClass::hostFound()
{
    // 处理主机查找事件
}

void MyClass::socketStateChanged(QAbstractSocket::SocketState state)
{
    // 处理状态变化
}

void MyClass::socketErrorOccurred(QAbstractSocket::SocketError socketError)
{
    // 处理错误
}

By connecting these signals and the corresponding slot functions, the event response and processing of the QTcpSocket object can be realized.

Chapter 2 UDP Communication Example

Here is a simple sample code showing how to use Qt for UDP communication:

Server code:

// Server.h
#ifndef SERVER_H
#define SERVER_H

#include <QObject>
#include <QUdpSocket>

class Server : public QObject
{
    Q_OBJECT
public:
    explicit Server(QObject *parent = nullptr);

public slots:
    void readyRead();

private:
    QUdpSocket *udpSocket;
};



// Server.cpp
#include "Server.h"

Server::Server(QObject *parent) : QObject(parent)
{
    //创建udp socket对象
    udpSocket = new QUdpSocket(this);

    //由于是服务器,需要绑定socket的IP地址和端口号
    udpSocket->bind(QHostAddress::Any, 12345);

    //在socket对象和Server应用程序之间建立信号与回调函数机制
    //当Server中有数据时,socket自动发送信号给Server应用程序,自动调用Server注册到Socket中的回调函数
    connect(udpSocket, &QUdpSocket::readyRead, this, &Server::readyRead);
}

// Server的应用程序
void Server::readyRead()
{
    while (udpSocket->hasPendingDatagrams()) {
        //为读取/接收数据准备缓冲区
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        
        //为获取发送方信息准备对象
        QHostAddress senderAddress;
        quint16 senderPort;
        
        //应用程序从socket中读取数据
        udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
        qDebug() << "Received data:" << datagram << "from" << senderAddress.toString() << ":" << senderPort;

        // 在这里可以对接收到的数据进行处理

        // 回复客户端: 即向socket写数据
        udpSocket->writeDatagram("Server response", senderAddress, senderPort);
    }
}

Client code:

// Client.h
#ifndef CLIENT_H
#define CLIENT_H

#include <QObject>
#include <QUdpSocket>

class Client : public QObject
{
    Q_OBJECT
public:
    explicit Client(QObject *parent = nullptr);

public slots:
    void readyRead();

private:
    QUdpSocket *udpSocket;
};



// Client.cpp
#include "Client.h"

Client::Client(QObject *parent) : QObject(parent)
{
    
    //创建udp socket对象
    udpSocket = new QUdpSocket(this);

    //当udpSocket中有数据时,TCP/IP协议栈自动会给该socket发送事件
    //该socket对象自动会发送readyRead的信号,请求应用程序读取数据
    //应用程序只需要把自己对象的槽函数挂接到新创建的socket对象的readyRead事件上即可
    //有socket中有数据时,创建的socket对象自动会发送readyRead事件,这是QT的网络通信协作栈保证的
    connect(udpSocket, &QUdpSocket::readyRead, this, &Client::readyRead);
}

//readyRead是应用程序挂接到socket上,读取socket数据的函数
//本质上是一个回调函数而已
void Client::readyRead()
{
    //client检查socket中是否有数据
    //如果有数据,则一直读数据,然后数据读完
    //如果没有数据,则直接退出
    while (udpSocket->hasPendingDatagrams()) 
    {
        //准备好数据接收buffer
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());

        //获取数据发送端的IP地址和端口号
        QHostAddress senderAddress;
        quint16 senderPort;
 
       //从upd socket读取数据,并获得数据发送端的信息
       udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
       
        qDebug() << "Received data:" << datagram << "from" << senderAddress.toString() << ":" << senderPort;

        // 在这里可以对接收到的数据进行处理
        // .............................
        // .............................
    }
}

Chapter 3 TCP Communication Code Example

Special Note:

The socket of TCP is similar to the communication of UDP. The application class object registers a callback function with the socket class object. When a certain event occurs in the socket object, the socket object automatically calls the corresponding application program to process the socket related signal through the previously registered callback function (signal and slot). ! !

Here is a simple sample code showing how to use Qt for TCP/IP communication:

Server side code:

// Server.h
#ifndef SERVER_H
#define SERVER_H

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

class Server : public QObject
{
    Q_OBJECT
public:
    explicit Server(QObject *parent = nullptr);

public slots:
    void newConnection();
    void readyRead();
    void disconnected();

private:
    QTcpServer *tcpServer;
    QTcpSocket *clientSocket;
};

// Server.cpp
#include "Server.h"

Server::Server(QObject *parent) : QObject(parent)
{
    tcpServer = new QTcpServer(this);

    if (!tcpServer->listen(QHostAddress::Any, 12345)) {
        qDebug() << "Server could not start!";
    } else {
        qDebug() << "Server started!";
    }

    connect(tcpServer, &QTcpServer::newConnection, this, &Server::newConnection);
}

void Server::newConnection()
{
    clientSocket = tcpServer->nextPendingConnection();
    connect(clientSocket, &QTcpSocket::readyRead, this, &Server::readyRead);
    connect(clientSocket, &QTcpSocket::disconnected, this, &Server::disconnected);
    qDebug() << "Client connected!";
}

void Server::readyRead()
{
    QByteArray data = clientSocket->readAll();
    qDebug() << "Received data:" << data;

    // 在这里可以对接收到的数据进行处理

    // 回复客户端
    clientSocket->write("Server response");
    clientSocket->flush();
}

void Server::disconnected()
{
    qDebug() << "Client disconnected!";
    clientSocket->deleteLater();
}

Client code:

// Client.h
#ifndef CLIENT_H
#define CLIENT_H

#include <QObject>
#include <QTcpSocket>

class Client : public QObject
{
    Q_OBJECT
public:
    explicit Client(QObject *parent = nullptr);

public slots:
    void connected();
    void disconnected();
    void readyRead();

private:
    QTcpSocket *tcpSocket;
};

// Client.cpp
#include "Client.h"

Client::Client(QObject *parent) : QObject(parent)
{
    tcpSocket = new QTcpSocket(this);
    connect(tcpSocket, &QTcpSocket::connected, this, &Client::connected);
    connect(tcpSocket, &QTcpSocket::disconnected, this, &Client::disconnected);
    connect(tcpSocket, &QTcpSocket::readyRead, this, &Client::readyRead);

    tcpSocket->connectToHost("127.0.0.1", 12345);
}

void Client::connected()
{
    qDebug() << "Connected to Server!";
    tcpSocket->write("Hello from Client!");
    tcpSocket->flush();
}

void Client::disconnected()
{
    qDebug() << "Disconnected from Server!";
}

void Client::readyRead()
{
    QByteArray data = tcpSocket->readAll();
    qDebug() << "Received data:" << data;

    // 在这里可以对接收到的数据进行处理
}

In the example above, the server listens on port 12345 on all network interfaces with IP address "Any" (0.0.0.0). The client connects to port 12345 on "127.0.0.1" (the local loopback address).

When the client connects to the server, the server will print "Client connected!". When the server receives the data from the client, it will print the data on the console, and then reply to the client. After the client receives the reply from the server, it will print the data on the console.

Make sure to start the server before the client connects so that it can receive the client's connection request.

This is just a simple example, you can modify and extend it as needed. Please note that in actual use, errors and exceptions should be

Guess you like

Origin blog.csdn.net/HiWangWenBing/article/details/131747081