• Qt的网络连接方式


    引入

    Qt支持广泛的网络通信方式,包括HTTP/TP协议、TCP连接、UDP连接等等,都可以在Qt netWork模块中实现;

    .pro文件中加上QT += network就可以直接使用这个模块了

    而且Qt是支持C++11的原生写法的,所以C++原生的很多库也能用,你甚至可以直接写socket连接;

    network模块的类的布局

    命名空间:

    命名说明
    QPasswordDigestor包含可用于生成哈希或键的函数
    QSsl声明Qt网络中所有SSL类通用的枚举

    类成员:

    命名说明
    QAbstractNetworkCache缓存实现的接口
    QAbstractSocket所有套接字类型通用的基本功能
    QAuthenticator身份验证对象
    QDns域名记录,存储有关域名记录的信息
    QDnsHostAddressRecord存储有关主机地址记录的信息
    QDnsLookup表示 DNS 查找
    QDnsMailExchangeRecord存储有关 DNS MX 记录的信息
    QDnsServiceRecord存储有关 DNS SRV 记录的信息
    QDnsTextRecord存储有关 DNS TXT 记录的信息
    QDtls此类为 UDP 套接字提供加密
    QDtlsClientVerifier此类实现服务器端 DTLS Cookie 生成和验证
    QDtls此类定义 DTLS Cookie 生成器的参数
    QHost地址IP地址
    QHostInfo用于主机名查找的静态函数
    QHstsPolicy指定主机支持 HTTP 严格传输安全策略 (HSTS)
    QHttp2配置控制 HTTP/2 参数和设置
    QHttpMultiPart类似于要通过 HTTP 发送的 MIME 多部分消息
    QHttpPart保存要在 HTTP 多部分 MIME 消息中使用的正文部分
    QLocalServer基于本地套接字的服务器
    QLocalSocket本地套接字
    QNetworkAccessManager允许应用程序发送网络请求和接收答复
    QNetworkAddressEntry存储网络接口支持的一个 IP 地址及其关联的网络掩码和广播地址
    QNetworkCacheMetaData缓存信息
    QNetworkCookie保存一个网络 Cookie
    QNetworkCookieJar实现了一个简单的 QNetworkCookie 对象罐
    QNetworkDatagramUDP 数据报的数据和元数据
    QNetworkDiskCache非常基本的磁盘缓存
    QNetworkInterface主机的 IP 地址和网络接口列表
    QNetworkProxy网络层代理
    QNetworkProxyFactory细粒度代理选择
    QNetworkProxyQuery用于查询套接字的代理设置
    QNetworkReply包含使用 QNetworkAccessManager 发送的请求的数据和标头
    QNetworkRequest保存要使用 QNetworkAccessManager 发送的请求
    QOcspResponse此类表示联机证书状态协议响应
    QSctpServer基于 SCTP 的服务器
    QSctpSocketSCTP 插座
    QSslCertificate用于 X509 证书的便捷 API
    QSslCertificateExtension用于访问 X509 证书扩展的 API
    QSslCipher表示 SSL 加密密码
    QSslConfiguration保存 SSL 连接的配置和状态
    QSslDiffieHellmanParameters用于服务器的 Diffie-Hellman 参数接口
    QSslEllipticCurve表示供椭圆曲线密码算法使用的椭圆曲线
    QSslError断续器错误
    QSslKey私钥和公钥接口
    QSslPreSharedKeyAuthenticator预共享密钥 (PSK) 密码套件的身份验证数据
    QSslSocket客户端和服务器的 SSL 加密套接字
    QTcpServer基于 TCP 的服务器
    QTcpSocketTCP 套接字
    QUdpSocketUDP 插座

    虽然Qt提供了这么多的类供我们使用,但在实际项目中我们不会用到这么多的接口类,也不用专门去记它,用的时候查一查,经常用的就那么几个,
    接下来我们来看看一般的使用方法和常用的几个接口类。

    网络接口信息获取

    QNetwork提供 Q H o s t I n f o QHostInfo QHostInfo类提供的静态函数,进行主机名的查找,使用OS提供的查找机制获取一个与主机名关联的IP地址或者获取一个IP地址关联的主机名

    QHostInfo中的静态函数 f r o m N a m e ( ) fromName() fromName()(会阻塞并返回QHostInfo一个对象,这个对象的address函数可以获取其主机的IP地址列表)

    l o o k u p H o s t lookupHost lookupHost(异步获取,每找到主机就会发送信号)可以进行主机信息的获取

    主要应用代码如下:

      //QHostInfo 获取主机名查找
        QString localHostName = QHostInfo::localHostName();//获取了本地主机名
    
    //通过获取主机名 然后两种方式获取其IP地址
    
        //fromName 寻找主机信息
        QHostInfo info = QHostInfo::fromName(localHostName);
        info.addresses();//获取与主机名相关的IP地址列表 包含了ipv4与ipv6
    
        //lookupHost查找IP地址
        QHostInfo::lookupHost(localHostName, this, SLOT(lookedUp(QHostInfo)));  
    	
    void MainWindow::lookedUp(const QHostInfo &host)  //对应的槽函数
    {
        if (host.error() != QHostInfo::NoError) {  //先判断是否出错
            qDebug() << "Lookup failed:" << host.errorString();
            return;
        }
        foreach (const QHostAddress &address, host.addresses()) //获取地址
            qDebug() << "Found address:" << address.toString();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    提供了 Q N e t w o r k I n t e r f a c e QNetworkInterface QNetworkInterface类获取主机的IP地址列表和网络接口信息。

    Q N e t w o r k I n t e r f a c e QNetworkInterface QNetworkInterface类代表了运行当前程序的主机的网络接口

    // 获取所有网络接口的列表
        QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
        // 遍历每一个网络接口
        foreach (QNetworkInterface interface, list)
        {
            // 接口名称
            qDebug() << "Name: " << interface.name();
            // 硬件地址
            qDebug() << "HardwareAddress: " << interface.hardwareAddress();
            //可以通过它获取所有ip地址
            qDebug()<< "Ip address"<<interface.allAddresses();
            // 获取IP地址条目列表,每个条目中包含一个IP地址,一个子网掩码和一个广播地址
            QList<QNetworkAddressEntry> entryList = interface.addressEntries();//addressEntries()可以返回一个QNetworkAddressEntry对象的列表
            //QNetworkAddressEntry类保存了一个网络支持的IP 以及该IP地址相关的子网掩码和广播地址
            // 遍历每一个IP地址条目
            foreach (QNetworkAddressEntry entry, entryList)
            {
                // IP地址
                qDebug() << "IP Address: " << entry.ip().toString();
                // 子网掩码
                qDebug() << "Netmask: " << entry.netmask().toString();
                // 广播地址
                qDebug() << "Broadcast: " << entry.broadcast().toString();
            }
        }
    
    • 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

    UDP连接

    这种方式最简单,数据包发过去就好了,也不需要他回复,不用管这个数据包到底有没有送到,是一种不可靠的连接方式

    发送端:

     QUdpSocket *sender;
        sender = new QUdpSocket(this);
        
        QByteArray datagram = "hello world!";
        sender->writeDatagram(datagram.data(), datagram.size(),QHostAddress::Broadcast, 45454); //广播地址   端口号
        //参数分别为: 数据,数据长度,主机地址,端口号为address的主机的port端口
        //意义是发送size大小的数据包data到地址
        //不建议发送大于512字节的数据报;端口号最好取1024以上的,最大为65535 2的16次方
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接收端:

     QUdpSocket *sender;
        receiver = new QUdpSocket(this);
        receiver->bind(45454, QUdpSocket::ShareAddress);//和发送端端口号一致  不需指定IP。默认支持所有IPV4,绑定模式表明允许其他服务器
        //每当有数据报来时,都会触发readyRead()
        connect(receiver, SIGNAL(readyRead()), this, SLOT(processPendingDatagram()));
    
    // 处理等待的数据报
    void Receiver::processPendingDatagram()
    {
        // 拥有等待的数据报
        while(receiver->hasPendingDatagrams())    //hasPendingDatagrams()判断是否还有等待的数据报
        {
            QByteArray datagram;
            // 让datagram的大小为等待处理的数据报的大小,这样才能接收到完整的数据
            datagram.resize(receiver->pendingDatagramSize());//pendingDatagramSize() 当前数据包大小
            // 接收数据报,将其存放到datagram中
            receiver->readDatagram(datagram.data(), datagram.size());//readDatagram将不大于指定长度的数据保存到datagram.data()
            ui->label->setText(datagram);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    TCP连接

    TCP连接就是面向数据流和连接的可靠传输协议了,学了计网的对这个都熟悉,我们使用接口类写连接就不需要我们自己用socket手怼三次握手和四次挥手了

    服务端

    建立连接:

    服务端不主动建立连接,他是监听连接的端口,有客户端发送过来的连接请求才会跟他建立全双工连接

    先创建一个QTcpServer对象QTcpServer tcp_server;

    开启TCP服务器,监听所有地址,端口号:
    (监听哪个单独的端口大家再详细看函数的参数列表)

    tcp_server.listen(QHostAddress::Any,port);
    
    • 1

    客户端向服务器发送连接请求时,发送的信号处理的槽函数:

    connect(&tcpserver,SLGNAL(newConnection()),this,SLOT(answerConnection()自定义槽函数));
    
    void answerConnection()
    {
        //获取和客户端通信的套接字
        QTcpServer* client_socket = tcp_server.nextPendingConnection();
        //保存客户端套接字
        client_list.append(client_socket);
        //客户端向服务器发送消息时,触发readyread信号
        connect(client_socket,SIGNAL,(readyread()),this,SLOT(answerReadyread()));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接收客户端发来的信息:

    void answerReadyread()
    {
        //遍历检查哪个客户端有消息
        for(int i = 0;i < client_list.size();i++)
        {
            //获取等待套接字字节数,没有消息返回0
            if(client_list.at[i]->bytesAvailable())
            {
                QByteArray buf = client_list.at(i)->readALL();//读取保存到buf
                ui->listWidget->addItem(buf);//显示到界面
                sendMessage(buf);//发送给其他客户端
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    客户端

    建立连接:

    QTcpSocket tcp_socket;//创建和服务器通信的套接字
     
    tcp_socket.connectToHost(server_ip,server_port);//向服务器发送连接请求
     
    //向服务器发送连接时会发送信号connected
     
    connect(&tcp_socket,SIGNAL(connected()),this,SLOT(answerConnected()));
     
    //收到服务器转发消息时会发送readyRead()信号
     
    connect(&tcp_socket,SIGNAL(readyRead()),this,SLOT(answerReadyRead()));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接收消息:

    void answerReadyRead()
    {
        if(tcp_socket.bytesAvailable())//如果有消息
        {
            QByteArray buf = tcp_socket.readAll();//将消息内容读出来
            ui->listWidget->addItem(buf);//做什么操作就是看业务需求了
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    mysql 日期函数
    MIT6.5830 Lab0-Go tutorial实验记录(三)
    Linux用户与权限管理命令
    计算机组成原理——存储系统の选择题整理
    带支付的客服系统2.0源码|多语言客服|Saas客服|多商户
    牛客网刷题——JAVA
    linux常用服务配置、网络配置 和 基于FTP的上传和下载的几种方式
    qml入门
    六十六、vue组件
    C++日期和时间编程总结
  • 原文地址:https://blog.csdn.net/Albert_weiku/article/details/125544882