qt 是一个跨平台c 图形界面开发库,利用qt可以快速开发跨平台窗体应用程序,在qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用qudpsocket
组件实现基于udp的网络通信功能。
与qtcpsocket
组件功能类似,qudpsocket
组件是 qt 中用于实现用户数据报协议(udp,user datagram protocol)通信的类。udp 是一种无连接的、不可靠的数据传输协议,它不保证数据包的顺序和可靠性,但具有低延迟和简单的特点。
以下是 qudpsocket
类的完整函数及其简要解释:
函数 | 描述 |
---|---|
qudpsocket(qobject *parent = nullptr) | 构造函数,创建一个新的 qudpsocket 对象。 |
~qudpsocket() | 析构函数,释放 qudpsocket 对象及其资源。 |
void bind(const qhostaddress &address, quint16 port, bindmode mode = defaultforplatform) | 将套接字绑定到指定的本地地址和端口。 |
void close() | 关闭套接字。 |
bool joinmulticastgroup(const qhostaddress &groupaddress, const qnetworkinterface &iface = qnetworkinterface()) | 加入多播组。 |
bool leavemulticastgroup(const qhostaddress &groupaddress, const qnetworkinterface &iface = qnetworkinterface()) | 离开多播组。 |
qint64 pendingdatagramsize() const | 返回下一个待读取的数据报的大小。 |
qint64 readdatagram(char *data, qint64 maxsize, qhostaddress *address = nullptr, quint16 *port = nullptr) | 读取数据报。 |
qbytearray readdatagram(qint64 maxsize, qhostaddress *address = nullptr, quint16 *port = nullptr) | 读取数据报,返回 qbytearray 对象。 |
qint64 writedatagram(const char *data, qint64 size, const qhostaddress &address, quint16 port) | 发送数据报。 |
qint64 writedatagram(const qbytearray &datagram, const qhostaddress &address, quint16 port) | 发送数据报,接受 qbytearray 对象。 |
qabstractsocket::socketstate state() const | 返回套接字的当前状态。 |
qabstractsocket::sockettype sockettype() const | 返回套接字的类型。 |
bool isvalid() const | 如果套接字有效,则返回 true;否则返回 false。 |
int error() const | 返回套接字的当前错误代码。 |
qhostaddress localaddress() const | 返回本地地址。 |
quint16 localport() const | 返回本地端口。 |
int readbuffersize() const | 返回读取缓冲区的大小。 |
void setreadbuffersize(int size) | 设置读取缓冲区的大小。 |
qnetworkinterface multicastinterface() const | 返回多播组的网络接口。 |
void setmulticastinterface(const qnetworkinterface &iface) | 设置多播组的网络接口。 |
bool haspendingdatagrams() const | 如果有待读取的数据报,则返回 true;否则返回 false。 |
bool isreadable() const | 如果套接字可读,则返回 true;否则返回 false。 |
bool iswritable() const | 如果套接字可写,则返回 true;否则返回 false。 |
bool setsocketdescriptor(int socketdescriptor, qudpsocket::socketstate socketstate = connectedstate, qiodevice::openmode openmode = readwrite) | 设置套接字描述符。 |
int socketdescriptor() const | 返回套接字描述符。 |
bool waitforreadyread(int msecs = 30000) | 等待套接字可读取数据。 |
bool waitforbyteswritten(int msecs = 30000) | 等待套接字已写入指定字节数的数据。 |
void ignoresslerrors(const qlist | 忽略 ssl 错误。 |
void abort() | 强制关闭套接字。 |
qnetworkproxy proxy() const | 返回套接字的代理设置。 |
void setproxy(const qnetworkproxy &networkproxy) | 设置套接字的代理设置。 |
qstring errorstring() const | 返回套接字的错误消息字符串。 |
这些函数提供了在 udp 通信中使用 qudpsocket
的各种功能,包括绑定、发送和接收数据报、设置和获取套接字的状态等。
1.初始化部分
在初始化部分我们首先通过new qudpsocket
来实现创建udp对象,qudpsocket
构造函数的函数原型如下:
qudpsocket::qudpsocket(qobject * parent = nullptr)
如上构造函数创建一个新的 qudpsocket
对象。如果提供了 parent
参数,则会将新创建的 qudpsocket
对象添加到 parent
对象的子对象列表中,并且在 parent
对象被销毁时自动销毁 qudpsocket
对象。如果没有提供 parent
参数,则 qudpsocket
对象将不会有父对象,并且需要手动管理其生命周期。
初始化结束后,则下一步需要调用bind()
,bind()
函数是 qudpsocket
类的一个成员函数,用于将套接字绑定到特定的本地地址和端口。它的函数原型如下:
void qudpsocket::bind(const qhostaddress &address, quint16 port, bindmode mode = defaultforplatform)
address
:要绑定的本地地址,通常是qhostaddress::any
,表示绑定到所有可用的网络接口。port
:要绑定的本地端口号。mode
:绑定模式,指定套接字的行为。默认值是defaultforplatform
,表示使用平台默认的绑定模式。
该函数允许 qudpsocket
在本地网络接口上监听传入的数据报。一旦调用了 bind()
函数,qudpsocket
就可以接收来自指定地址和端口的数据报。
在调用 bind()
函数之后,如果成功绑定了指定的地址和端口,套接字将处于 boundstate
状态。如果出现错误,可以通过检查 error()
函数获取错误代码,并通过 errorstring()
函数获取错误消息。
接着我们通过connect()
函数依次绑定套接字到statechanged
状态改变信号,以及readyread()
读取信号上,这段初始化代码如下所示;
mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent) , ui(new ui::mainwindow) { ui->setupui(this); udpsocket=new qudpsocket(this); // 生成随机整数 包含2000 - 不包含65534 int randomint = qrandomgenerator::global()->bounded(2000, 65534); if(udpsocket->bind(randomint)) { this->setwindowtitle(this->windowtitle() " | 地址: " getlocaladdress() " 绑定端口:" qstring::number(udpsocket->localport())); } connect(udpsocket,signal(statechanged(qabstractsocket::socketstate)),this,slot(onsocketstatechange(qabstractsocket::socketstate))); onsocketstatechange(udpsocket->state()); connect(udpsocket,signal(readyread()),this,slot(onsocketreadyread())); }
接着切换到读取信号所对应的槽函数上,onsocketreadyread
是我们自定义的一个槽,该槽函数功能如下所示;
// 读取收到的数据报 void mainwindow::onsocketreadyread() { while(udpsocket->haspendingdatagrams()) { qbytearray datagram; datagram.resize(udpsocket->pendingdatagramsize()); qhostaddress peeraddr; quint16 peerport; udpsocket->readdatagram(datagram.data(),datagram.size(),&peeraddr,&peerport); qstring str=datagram.data(); qstring peer="[消息来自 " peeraddr.tostring() ":" qstring::number(peerport) "] | "; ui->plaintextedit->appendplaintext(peer str); } }
首先在代码中调用pendingdatagramsize
函数,pendingdatagramsize()
是 qudpsocket
类的一个成员函数,用于获取下一个待读取的数据报的大小。它的函数原型如下:
qint64 qudpsocket::pendingdatagramsize() const
该函数返回一个 qint64
类型的值,表示下一个待读取的数据报的大小(以字节为单位)。如果没有待读取的数据报,或者发生了错误,该函数将返回 -1。
通常,可以在调用 readdatagram()
函数之前调用 pendingdatagramsize()
函数来获取下一个待读取的数据报的大小。这样可以为数据缓冲区分配正确大小的空间,以确保完整地读取数据报。
当有了待读取字节后,接着就可以直接通过调用readdatagram
函数来从套接字中读取数据报,readdatagram()
是 qudpsocket
类的一个成员函数,它有几个重载形式,其中最常用的是:
qint64 qudpsocket::readdatagram(char * data, qint64 maxsize, qhostaddress * address = nullptr, quint16 * port = nullptr)
该函数用于读取数据报并将其存储到指定的缓冲区 data
中,最多读取 maxsize
个字节的数据。可选参数 address
和 port
用于返回数据报的源地址和端口号。如果不需要这些信息,可以将它们设置为 nullptr
。
函数返回实际读取的字节数,如果发生错误,返回 -1。要查看错误信息,可以使用 error()
和 errorstring()
函数。
另外,还有一个更简单的重载形式:
qbytearray qudpsocket::readdatagram(qint64 maxsize, qhostaddress * address = nullptr, quint16 * port = nullptr)
这个重载函数直接返回一个 qbytearray
对象,其中包含了读取的数据报。
2.单播与广播消息
单播(unicast)和广播(broadcast)是网络通信中常见的两种数据传输方式,它们在数据包的传输范围和目标数量上有所不同。
单播(unicast)
单播是一种一对一的通信方式,其中数据包从一个发送者传输到一个接收者。在单播通信中,数据包只发送到目标主机的网络接口,并且只有目标主机能够接收和处理这个数据包。
- 一对一通信:每个数据包只有一个发送者和一个接收者。
- 目标明确:数据包只发送到特定的目标主机,其他主机不会接收到这个数据包。
- 点到点通信:适用于直接通信的场景,如客户端与服务器之间的通信。
当按钮发送消息被点击后,则是一种单播模式,通常该模式需要得到目标地址与端口号,并通过调用writedatagram
来实现数据的发送,该函数通过传入三个参数,分别是发送字符串,目标地址与目标端口来实现一对一推送。
void mainwindow::on_pushbutton_clicked() { qhostaddress targetaddr(ui->lineedit_addr->text()); qstring portstring = ui->lineedit_port->text(); quint16 targetport = portstring.toushort(); qstring msg=ui->lineedit_msg->text(); qbytearray str=msg.toutf8(); // 发送数据报 udpsocket->writedatagram(str,targetaddr,targetport); ui->plaintextedit->appendplaintext("[单播消息] | " msg); }
广播(broadcast)
广播是一种一对多的通信方式,其中数据包从一个发送者传输到同一网络中的所有主机。在广播通信中,数据包被发送到网络中的所有主机,并且所有的主机都能够接收和处理这个数据包。
- 一对多通信:每个数据包有一个发送者,但可以有多个接收者。
- 目标不明确:数据包被发送到网络中的所有主机,不需要知道接收者的具体地址。
- 广播域:在局域网中进行广播,只有在同一广播域内的主机才能接收到广播消息。
- 网络负载:在大型网络中使用广播可能会产生大量的网络流量,影响网络性能。
当按钮广播消息被点击后,则同样是调用writedatagram
函数与,唯一的区别在于第二个参数并未指定地址,而是使用了qhostaddress::broadcast
来代替,意味着只要端口是一致的则对所有的客户推送消息,其他保持不变。
void mainwindow::on_pushbutton_2_clicked() { // 广播地址 qstring portstring = ui->lineedit_port->text(); quint16 targetport = portstring.toushort(); qstring msg=ui->lineedit_msg->text(); qbytearray str=msg.toutf8(); udpsocket->writedatagram(str,qhostaddress::broadcast,targetport); ui->plaintextedit->appendplaintext("[广播消息] | " msg); }
读者可自行运行两次客户端,此时的端口将会随机分配,当指定对端端口后就可以向其发送数据,如下图所示;具体实现细节,请参考文章附件。
以上就是c qt开发之使用qudpsocket实现udp网络通信的详细内容,更多关于qt qudpsocket udp网络通信的资料请关注其它相关文章!