QT之QUdpSocket学习
最近,因为公司的业务需求,需要用到 socket 的 udp 通信协议,特意学习了一下,这里分享给大家。
一、QT 的 socket 家族
这里首先给大家介绍一下 QT 的 socket 家族,结构图大致如下图所示:
最主要的是 QAbstractSocket 类,它是 QUdpSocket 和 QTcpSocket 的父类,QTcpSocket 类又包含了两个子类 QSctpSocket 和 QSslSocket。
二、QUdpSocket 的使用
以下为使用步骤:
- 在 pro 或者 pri文件中引入QT 的 network 网络模块:
//修改之前
QT += core gui
//修改之后
QT += core gui network
- 在文件头部或者头文件中引入 QUdpSocket 模块:
#include<QUdpSocket>
- 定义两个 QUdpSocket 指针对象,并初始化:
QUdpSocket* send_udp = new QUdpSocket(this);
QUdpSocket* receive_udp = new QUdpSocket(this);
- 使用 udp 协议接收数据,用的 qDebug() 将接收到的数据打印到终端,这里提供两种方式:
方法一:使用 receiveDatagram() 函数接收数据,接收到的中文数据需要解码,否则为16进制数据(该方法接收到的数据容错率极低,近乎为0)
//设置接收监听地址和端口,这里用的是本机ip
receive_udp -> bind(QHostAddress::LocalHost, 8088);
//绑定监听事件
connect(receive_udp, &QUdpSocket::readyRead, [this](){
while (receive_udp -> hasPendingDatagrams()) {
datagram = receive_udp -> receiveDatagram();
QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
qDebug() << utf8 -> toUnicode(datagram.data());
}
});
方法二:使用 readDatagram() 和 pendingDatagramSize() 函数接收数据,接收到的数据无需解码即可使用(该方法接收到的数据容存在一定的容错率,虽然也能完全接受数据,但是在接收到的数据后方有时存在一些乱码信息)
//设置接收监听地址和端口,这里用的是本机ip
receive_udp -> bind(QHostAddress::LocalHost, 8088);
//绑定监听事件
connect(receive_udp, &QUdpSocket::readyRead, [this](){
while (receive_udp -> hasPendingDatagrams()) {
int size = int(receive_udp -> pendingDatagramSize());
char* pBuffer = new char[size + 1];//分配报文大小的内存
memset(pBuffer, 0, size + 1);
receive_udp -> readDatagram(pBuffer, size);
qDebug() << pBuffer;
}
});
官方推荐使用用法:
void Server::initSocket() {
udpSocket = new QUdpSocket(this);
udpSocket -> bind(QHostAddress::LocalHost, 7755);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
void Server::readPendingDatagrams() {
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
//这里最好用 long 包含一下udpSocket -> pendingDatagramSize(),否则会有警告
datagram.resize(udpSocket -> pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket -> readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
processTheDatagram(datagram);
}
}
- 使用 udp 协议发送数据:
QString s = "";//字符串的类型可以根据需要自行定义
//writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port)
//该方式发送数据,接收到的中文乱码且解码后少字
send_udp -> writeDatagram(s.toStdString().c_str(), s.length(), QHostAddress::LocalHost, 8088);
//writeDatagram(const QByteArray & datagram, const QHostAddress & host, quint16 port)
//需要发中文,建议使用以下方式
send_udp -> writeDatagram(s.toUtf8(), QHostAddress::LocalHost, 8088);
- 这里有一个写好的案例可以参考 BDYSocket.zip
三、注意事项
- 监听端口最好使用 1024 以上的,1024 以下的一般都是给系统用的;
- 发送中文数据用 QByteArray 类型数据,使用字符数组接收会乱码;
- 使用 receiveDatagram() 函数接收中文数据时,需要对数据进行解码,否则出来的是十六进制数据;
- 使用 UDP 协议收发数据注意一定要先开启接收监听,然后在发送数据,否则收不到数据的。
学习分享,一起成长!接触QT的时间不长,目前差不多有两个月了,有不足之处,欢迎大佬指出来,我会进行更正。有问题可以发送邮件至 mjzhutianxiu@163.com ,不定时上线查收。