Qt支持广泛的网络通信方式,包括HTTP/TP协议、TCP连接、UDP连接等等,都可以在Qt netWork
模块中实现;
在.pro
文件中加上QT += network
就可以直接使用这个模块了
而且Qt是支持C++11的原生写法的,所以C++原生的很多库也能用,你甚至可以直接写socket
连接;
命名空间:
命名 | 说明 |
---|---|
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 对象罐 |
QNetworkDatagram | UDP 数据报的数据和元数据 |
QNetworkDiskCache | 非常基本的磁盘缓存 |
QNetworkInterface | 主机的 IP 地址和网络接口列表 |
QNetworkProxy | 网络层代理 |
QNetworkProxyFactory | 细粒度代理选择 |
QNetworkProxyQuery | 用于查询套接字的代理设置 |
QNetworkReply | 包含使用 QNetworkAccessManager 发送的请求的数据和标头 |
QNetworkRequest | 保存要使用 QNetworkAccessManager 发送的请求 |
QOcspResponse | 此类表示联机证书状态协议响应 |
QSctpServer | 基于 SCTP 的服务器 |
QSctpSocket | SCTP 插座 |
QSslCertificate | 用于 X509 证书的便捷 API |
QSslCertificateExtension | 用于访问 X509 证书扩展的 API |
QSslCipher | 表示 SSL 加密密码 |
QSslConfiguration | 保存 SSL 连接的配置和状态 |
QSslDiffieHellmanParameters | 用于服务器的 Diffie-Hellman 参数接口 |
QSslEllipticCurve | 表示供椭圆曲线密码算法使用的椭圆曲线 |
QSslError | 断续器错误 |
QSslKey | 私钥和公钥接口 |
QSslPreSharedKeyAuthenticator | 预共享密钥 (PSK) 密码套件的身份验证数据 |
QSslSocket | 客户端和服务器的 SSL 加密套接字 |
QTcpServer | 基于 TCP 的服务器 |
QTcpSocket | TCP 套接字 |
QUdpSocket | UDP 插座 |
虽然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();
}
提供了 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();
}
}
这种方式最简单,数据包发过去就好了,也不需要他回复,不用管这个数据包到底有没有送到,是一种不可靠的连接方式
发送端:
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次方
接收端:
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);
}
}
TCP连接就是面向数据流和连接的可靠传输协议了,学了计网的对这个都熟悉,我们使用接口类写连接就不需要我们自己用socket手怼三次握手和四次挥手了
建立连接:
服务端不主动建立连接,他是监听连接的端口,有客户端发送过来的连接请求才会跟他建立全双工连接
先创建一个QTcpServer对象QTcpServer tcp_server;
开启TCP服务器,监听所有地址,端口号:
(监听哪个单独的端口大家再详细看函数的参数列表)
tcp_server.listen(QHostAddress::Any,port);
客户端向服务器发送连接请求时,发送的信号处理的槽函数:
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()));
}
接收客户端发来的信息:
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);//发送给其他客户端
}
}
}
建立连接:
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()));
接收消息:
void answerReadyRead()
{
if(tcp_socket.bytesAvailable())//如果有消息
{
QByteArray buf = tcp_socket.readAll();//将消息内容读出来
ui->listWidget->addItem(buf);//做什么操作就是看业务需求了
}
}