【Qt初入江湖】Qt QTcpSocket 底层架构、原理详细描述

鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

Qt QTcpSocket是一个用于实现TCP协议的客户端和服务器端的类,它可以连接到指定的主机和端口,提供了丰富的方法和信号来发送和接收数据。QTcpSocket的底层架构由以下几个部分组成:

  1. QTcpSocketPrivate

QTcpSocketPrivate是QTcpSocket的私有类,它负责QTcpSocket的底层实现。QTcpSocketPrivate包含了一个QAbstractSocketEngine类型的成员变量,用于管理底层的套接字通信。在QTcpSocket的构造函数中,会创建一个QTcpSocketPrivate对象,并将其作为QTcpSocket的私有数据。

  1. QAbstractSocketEngine

QAbstractSocketEngine是一个抽象类,它定义了QTcpSocket底层套接字通信的接口。具体的套接字通信实现由各个平台的QAbstractSocketEngine子类来实现。在QTcpSocketPrivate中,会创建一个具体的QAbstractSocketEngine子类对象,用于实现QTcpSocket的底层套接字通信。

  1. QSocketNotifier

QSocketNotifier是一个Qt中用于通知文件描述符状态变化的类,它可以监视文件描述符的读写状态,并在状态发生变化时发送信号通知应用程序。在QTcpSocketPrivate中,会使用QSocketNotifier来监听底层套接字通信的读写状态,并在状态发生变化时发送信号通知QTcpSocket。

下面是 QTcpSocket 的基本实现架构图:

+-------------------+
|      QTcpSocket    |
+-------------------+
| - socketDescriptor|
+-------------------+
          /_\
           |
           | 继承
           |
+-------------------+
|      QAbstractSocket |
+-------------------+
| - socketState     |
| - socketError     |
| - readBuffer      |
| - writeBuffer     |
| - readNotifier    |
| - writeNotifier   |
| - exceptionNotifier|
+-------------------+
          /_\
           |
           | 继承
           |
+-------------------+
|       QObject     |
+-------------------+

可以看出,QTcpSocket 继承自 QAbstractSocket 和 QObject 两个类,其中 QAbstractSocket 提供了基本的套接字操作(如连接、断开连接、发送数据等),而 QObject 则提供了对象的基本功能(如信号和槽、对象名称等)。

在 QTcpSocket 类中,socketDescriptor 属性表示底层使用的套接字描述符,它是一个整数值。QTcpSocket 的构造函数中会通过 socket() 函数创建一个新的套接字,并将其与 socketDescriptor 属性关联起来。QTcpSocket 的 connectToHost() 函数会调用底层的 connect() 函数来建立 TCP 连接。QTcpSocket 的 bind() 函数会调用底层的 bind() 函数来将套接字绑定到指定的本地地址和端口上。QTcpSocket 的 listen() 函数会调用底层的 listen() 函数来开始监听连接请求。QTcpSocket 的 accept() 函数会调用底层的 accept() 函数来接受连接请求并创建一个新的套接字。

QTcpSocket 通过 readNotifier 和 writeNotifier 成员变量来监听套接字的可读和可写事件,当套接字有数据可读或可以写入数据时,就会触发相应的信号(如 readyRead 和 bytesWritten 信号)来通知应用程序。当套接字出现错误时,socketError 信号会被触发,应用程序可以通过该信号来处理错误。

在QTcpSocket中,我们可以使用以下方法来实现TCP客户端和服务器端的通信:

  1. connectToHost()

connectToHost()方法用于连接到指定的主机和端口号,它接受两个参数,第一个参数是一个字符串,表示要连接的主机名或IP地址,第二个参数是一个整数,表示要连接的端口号。例如:

QTcpSocket socket;
socket.connectToHost("www.example.com", 80);
  1. disconnectFromHost()

disconnectFromHost()方法用于断开与主机的连接,它不接受任何参数。例如:

QTcpSocket socket;
socket.disconnectFromHost();
  1. write()

write()方法用于向连接的主机发送数据,它接受一个字节数组作为参数,表示要发送的数据。例如:

QTcpSocket socket;
socket.write("Hello, world!");
  1. flush()

flush()方法用于刷新缓冲区,将缓冲区中的数据发送出去,它不接受任何参数。例如:

QTcpSocket socket;
socket.write("Hello, world!");
socket.flush();
  1. read()

read()方法用于从连接的主机读取数据,它接受一个整数作为参数,表示要读取的数据长度。例如:

QTcpSocket socket;
socket.connectToHost("www.example.com", 80);
socket.write("GET / HTTP/1.0\r\n\r\n");
socket.flush();
QByteArray data = socket.readAll();
  1. close()

close()方法用于关闭套接字,它不接受任何参数。例如:

QTcpSocket socket;
socket.close();
  1. waitForConnected()

waitForConnected()方法用于等待连接完成,它接受一个整数作为参数,表示等待的超时时间(毫秒)。例如:

QTcpSocket socket;
socket.connectToHost("www.example.com", 80);
if (socket.waitForConnected(5000)) {
    qDebug() << "Connected";
} else {
    qDebug() << "Connection timed out";
}
  1. waitForReadyRead()

waitForReadyRead()方法用于等待套接字有数据可读,它接受一个整数作为参数,表示等待的超时时间(毫秒)。例如:

QTcpSocket socket;
socket.connectToHost("www.example.com", 80);
socket.write("GET / HTTP/1.0\r\n\r\n");
socket.flush();
if(socket.waitForReadyRead(5000))) {
    QByteArray data = socket.readAll();
    qDebug() << data;
} else {
    qDebug() << "No data received";
}
  1. error()

error()方法用于获取套接字的错误代码,它返回一个QAbstractSocket::SocketError枚举类型的值。例如:

QTcpSocket socket;
socket.connectToHost("www.example.com", 80);
if (socket.waitForConnected(5000)) {
    qDebug() << "Connected";
} else {
    qDebug() << "Connection error:" << socket.error();
}

以上是QTcpSocket类的主要方法,除此之外还有许多其他方法和信号,可以根据实际需求来选择使用。以下是一个简单的QTcpSocket示例代码,演示了如何实现TCP客户端的通信:

#include <QTcpSocket>
#include <QDebug>

int main()
{
    QTcpSocket socket;
    socket.connectToHost("www.example.com", 80);
    if (socket.waitForConnected(5000)) {
        qDebug() << "Connected";
        socket.write("GET / HTTP/1.0\r\n\r\n");
        socket.flush();
        if (socket.waitForReadyRead(5000)) {
            QByteArray data = socket.readAll();
            qDebug() << data;
        } else {
            qDebug() << "No data received";
        }
    } else {
        qDebug() << "Connection error:" << socket.error();
    }
    socket.close();
    return 0;
}

这个示例代码实现了连接到www.example.com的80端口,发送一个HTTP GET请求,并读取服务器返回的数据。实际使用中,可以根据需要对代码进行修改和扩展。

猜你喜欢

转载自blog.csdn.net/feng1790291543/article/details/131806916