0%

QT之网络通信

本节主要介绍关于计算机网络通信以及QT实现TCP/UDP通信的内容

计算机网络体系结构模型

  • 除了标准的OSI七层模型以外,常见的网络层次划分还有TCP/IP四层协议它们之间的对应关系为:

    image-20241015150134322
  • 应用层:为操作系统或网络应用程序提供访问网络服务的接口,主要协议有FTP、HTTP、SMTP、SSH等

  • 传输层:为两台主机上的应用程序提供端到端的通信,有TCP/UDP传输协议

    • TCP可靠传输协议:TCP需要三步握手建立连接,TCP每次通信都会进行数据的校验
    • UDP不可靠传输协议:UDP不需要建立连接、UDP不会进行数据校验
  • 网络层:负责提供基本的数据封包传送功能,让每个数据包都能够到达目的主机,有IPV4/IPV6,3G/4G/5G等网络协议

  • 物理层:光纤、路由器、基站、网线、网卡……

  • 具体的理解可以见该视频20min开始的解释,还挺形象:24网络的基本概念_哔哩哔哩_bilibili


QT TCP网络编程

1.QTcpSocket Class客户端类

image-20241015160436834
  • 要想使用QTcpSocket必须先添加网络模块

    image-20241015160621520
  • 一些函数接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //1.连接服务器
    connectToHost(const QString &, quint16, QIODeviceBase::OpenMode, QAbstractSocket::NetworkLayerProtocol);
    connectToHost(const QHostAddress &, quint16, QIODeviceBase::OpenMode);
    //第一个参数为IP地址;第二个参数为端口号(在0~65535范围内);第三个参数OpenMode默认readwrite模式,不用管

    //2.数据发送
    write(const char *, qint64); //发送qint64大小(byte为基本单位)的数据到char *地址上
    write(const QByteArray &); //发送QByteArray类型的数据
    write(const char *); //直接发送字符数据

    //3.数接接收
    read(char *, qint64); //读取qint64大的数据到char*地址上
    read(qint64); //读取qin64大的数据并返回QByteArray类型
    readAll(); //读取所有数据并返回QByteArray类型
  • 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //1.创建一个客户端的通信对象
    QTcpSocket *socket = new QTcpSocket(this);

    //2.连接服务器
    socket -> connectToHost("192.168.25.2", 1000);

    //3.数据发送
    socket -> write("hello");

    //4.数据接收
    QByteArray rev_data = socket -> readAll();
    //其中数据的接收需要关联可读信号:readyReady()[每次有新数据可从设备的当前读取通道读取时,都会发出此信号。]
    connect(socket, SIGNAL(readyReady()), this, SLOT(read_data())); ///自己再编写一个read_data槽函数

2.QTcpServer Class服务器类

image-20241015163834101
  • 一些函数接口:

    1
    2
    3
    4
    5
    6
    7
    8
    //1.绑定并监听
    listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);

    //2.接收连接请求
    [signal] void QTcpServer::newConnection(); //每次有新连接可用时都会发出此信号,无论该连接是否已添加到待处理连接队列中

    //3.服务器产生新的对象
    nextPendingConnection(); //返回一个新的QTcpSocket对象
  • 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //1.创建一个服务器对象
    server = new QTcpServer(this);

    //2.开始监听
    if(server -> listen(QHostAddress::Any,6666)){
    qDebug() << “监听成功”;
    }
    else {
    qDebug() << “监听失败”;
    }

    //3.关联新的连接信号
    connect(server, SIGNAL(newConnection()), this, SLOT(accept_connect())); //自己编写连接后的处理函数accept_connect

    void accept_connect{
    //产生新的通信对象
    QTcpSocket *new_socket = server -> nextPendingConnection();

    //新的对象发送数据
    new_socket -> write("hello");

    //新的对象接收数据
    connect(new_socket, SIGNAL(readyRead()), this, SLOT(read_data()))
    };
  • 服务器处理客户端连接逻辑:下图很形象。注意:客户端和服务器是不会直接通信的!!!

    image-20241015165357650

QT UDP网络编程

  • UDP的通信流程:

    image-20241015175103157
  • UDP部分客户端与服务器端

    image-20241015174717122
  • 一些函数接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //1.发送数据的接口
    writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port);
    //data:需要发送的数据
    //size:数据的大小
    //address:接收端的IP
    //port:接收端的端口
    writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port);

    //2.绑定UDP socket
    bind(const QHostAddress &address, quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform); //其返回值为bool

    //3.读取数据
    qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr);
    //data:读取后数据的存放地址
    //maxSize:读取的数据最大值
    //address:发送者的IP地址
    //port:发送者的端口地址
    QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize = -1);
    //QNetworkDatagram 网络数据管理类
    //QHostAddress senderAddress() const; //发送者的IP
    //int senderPort() const; //发送者的端口
    //QByteArray data(); //接收的数据
  • 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    //1.创建一个UDP对象
    udp = new QUdpSocket(this);

    //2.发送UDP数据
    udp -> writeDatagram(ui -> lineEdit -> text().toUtf8(), QHostAddress("192.168.25.2"), 6666);

    //3.接收数据
    //3.1绑定UDP socket
    if(socket -> bind(QHostAddress::Any, 6666)){
    qDebug() << "绑定成功";
    }
    else{
    qDebug() <<"绑定失败";
    }
    //3.2关联可读信号
    connect(udp, SIGNAL(readyRead), this, SLOT(readPendingDatagrams));
    //3.3接收发送端的数据
    void readPendingDatagrams()
    {
    qDebug() << "有数据可读";

    //方法一
    char buf[1024] = {0};
    QHostAddress ip;
    unsigned short port = 0;
    socket -> readDatagram(buf, 1024, &ip, &port);
    qDebug() << buf;

    //方法二
    while (udpSocket->hasPendingDatagrams()) { //判断是否有网络数据
    //把所有数据读到datagram
    QNetworkDatagram datagram = udpSocket->receiveDatagram();
    //输出数据
    qDebug() << datagram.senderAddress().toString();
    qDebug() << datagram.senderPort();
    qDebug() << datagram.data();
    }
    }

Reference

欢迎来到ssy的世界