Qt学习(十五) |
您所在的位置:网站首页 › 滤波器概念龙头股 › Qt学习(十五) |
UDP通信是无连接的,与TCP通信相比,少了一步建立连接的过程,只要经过绑定,就可以直接进行数据的发送和接收。 在Qt的UDP通信中,由于少了连接这一个步骤,客户端和服务端没有太大区别,所以也可以看作只有发送端和接收端。无论是发送端还是接收端,都只有一个套接字,也就是QUdpSocket。此外,UDP通信中没有监听listen(),只有绑定bind(),往套接字中读写数据用的是readDatagram()和writeDatafram(),关闭套接字时同样是调用close()。 P.S:datagram是数据报 / 数据包 / 数据报文的意思 和TCP相同的地方是,发送端向接收端发送数据时,会触发接收端的readyRead()信号。 UDP收发消息的实现首先,为了方便测试需要绘制两个窗口,在它们之间互相通信: //WidgetA.h #ifndef WIDGETA_H #define WIDGETA_H #include #include #include #include class WidgetA : public QWidget { Q_OBJECT public: WidgetA(QWidget *parent = 0); ~WidgetA(); private: QLineEdit *p_ipEdit; QLineEdit *p_portEdit; QPushButton *p_connectButton; QTextEdit *p_sendBox; QPushButton *p_sendButton; QPushButton *p_closeButton; }; #endif // WIDGETA_H 复制代码 //WidgetA.cpp #include "WidgetA.h" #include WidgetA::WidgetA(QWidget *parent) : QWidget(parent) { this->resize(640,480); this->move(300,300); this->setWindowTitle("Port 9999"); QGridLayout *p_layout=new QGridLayout(this); p_ipEdit=new QLineEdit(this); p_portEdit=new QLineEdit(this); p_sendBox=new QTextEdit(this); p_sendButton=new QPushButton("send",this); p_closeButton=new QPushButton("close",this); p_layout->addWidget(p_ipEdit,0,0,1,10); p_layout->addWidget(p_portEdit,1,0,1,10); p_layout->addWidget(p_sendBox,2,0,8,10); p_layout->addWidget(p_sendButton,10,0,1,2); p_layout->addWidget(p_closeButton,10,9,1,1); } WidgetA::~WidgetA() { } 复制代码另一个窗口可以增加一个C++文件,用相同的代码实现,也可以直接new一个WidgetA对象,在main.cpp中为不同的对象绑定不同的端口。 //main.cpp #include "WidgetA.h" #include "WidgetB.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); WidgetA wa; WidgetB wb; wa.show(); wb.show(); return a.exec(); } 复制代码实现效果:
接着,创建通信套接字QUdpSocket: //绑定端口 p_udpSocket=new QUdpSocket(this); p_udpSocket->bind(9999); 复制代码 readDatagram()当接收方接收到数据时,会触发readyRead()信号,在与之对应的槽函数中,我们需要调用readDatagram()方法来获取发送方发送过来的数据报内容以及发送方的主机地址和端口号。 P.S: readDatagram()方法的有四个参数: 第一个参数是存储数据报内容的char型数组; 第二个参数是数据报的最大长度,超过这个长度的数据会丢失; 第三个参数是发送者的主机地址,类型为QHostAddress; 第四个参数是发送者的端口号,类型为qint16。 这个方法的返回值是成功读取的字符数。 void WidgetB::readData(){ //获取发送者的IP和端口号以及数据报内容 char array[1024]; //用于接收数据报内容的char型数据 QHostAddress m_ip; //用于接收发送方IP地址的变量 quint16 m_port; //用于接收发送方端口号的变量,注意是quint16类型 qint64 m_len=p_udpSocket->readDatagram(array,sizeof(array),&m_ip,&m_port); //组包 if(m_len>0){ QString str=QString("[%1:%2]:%3").arg(m_ip.toString()).arg(m_port).arg(array); //设置文本区内容 p_sendBox->setText(str); } } 复制代码P.S:端口号这里的类型要用quint16而不是qint16,否则会报错。 writeDatagram()当作为发送方发送数据时,需要从窗口中获取目标主机地址和端口号,然后调用writeDatagram()将数据写到通信套接字中: void WidgetB::sendData(){ //获取接收方的IP端口号 QString m_ip=p_ipEdit->text(); quint16 m_port=p_portEdit->text().toInt(); //获取文本区内 QString str=p_sendBox->toPlainText(); //往通信套接字中写数据 p_udpSocket->writeDatagram(str.toUtf8(),QHostAddress(m_ip),m_port); } 复制代码P.S:端口号的类型是quint16,而主机地址的类型是QHostAddress。 实现效果:
若想关闭UDP套接字,直接调用close()即可: void WidgetB::closeConnection(){ p_udpSocket->close(); } 复制代码实现效果:
UDP进行广播时,同一个局域网中的所有主机都能接收到数据报。但哪些应用程序会收到消息取决于端口号。 UDP的广播地址为255.255.255.255。 实现效果:
虽然IP设置为255.255.255.255,但IP地址为127.0.0.1且端口号为8888的通信套接字还是收到了消息。当然,同一局域网下其他主机端口号为8888的进程也能收到消息。 UDP组播我们在使用广播发送消息的时候会发送给所有用户,但是有些用户是不想接受消息的,这时候我们就应该使用组播,接收方只有先注册到组播地址中才能收到组播消息,否则则接受不到消息。 UDP中的组播地址必须是D类地址。D类地址有: 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用; 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet; 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效; 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。可以调用joinMultiGroup()方法来加入一个组播。但是加入组播之后,bind()中就不能再使用默认的主机地址了,必须指定QHostAddress,否则会有如下警告:
实现效果:
也可以使用pendingDatagramSize()方法来获取数据报的大小,根据返回值来准备对应大小的内存空间存放将要接收的数据。 完整代码: //WidgetA.h #ifndef WIDGETA_H #define WIDGETA_H #include #include #include #include #include class WidgetA : public QWidget { Q_OBJECT public: WidgetA(QWidget *parent = 0); ~WidgetA(); private: QLineEdit *p_ipEdit; QLineEdit *p_portEdit; QPushButton *p_connectButton; QTextEdit *p_sendBox; QPushButton *p_sendButton; QPushButton *p_closeButton; QUdpSocket *p_udpSocket; protected: void WidgetA::readData(); void WidgetA::sendData(); void WidgetA::closeConnection(); }; #endif // WIDGETA_H 复制代码 //WidgetA.cpp #include "WidgetA.h" #include #include WidgetA::WidgetA(QWidget *parent) : QWidget(parent) { //绘制界面 this->resize(640,480); this->move(200,300); this->setWindowTitle("Port 9999"); QGridLayout *p_layout=new QGridLayout(this); p_ipEdit=new QLineEdit(this); p_portEdit=new QLineEdit(this); p_sendBox=new QTextEdit(this); p_sendButton=new QPushButton("send",this); p_closeButton=new QPushButton("close",this); p_layout->addWidget(p_ipEdit,0,0,1,10); p_layout->addWidget(p_portEdit,1,0,1,10); p_layout->addWidget(p_sendBox,2,0,8,10); p_layout->addWidget(p_sendButton,10,0,1,2); p_layout->addWidget(p_closeButton,10,9,1,1); //绑定端口 p_udpSocket=new QUdpSocket(this); p_udpSocket->bind(QHostAddress::AnyIPv4,9999); p_udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2")); connect(p_udpSocket,&QUdpSocket::readyRead,this,&WidgetA::readData); connect(p_sendButton,&QPushButton::clicked,this,&WidgetA::sendData); connect(p_closeButton,&QPushButton::clicked,this,&WidgetA::closeConnection); } WidgetA::~WidgetA() { } void WidgetA::readData(){ //获取发送者的IP和端口号以及数据报内容 char array[1024]; QHostAddress m_ip; quint16 m_port; qint64 m_len=p_udpSocket->readDatagram(array,sizeof(array),&m_ip,&m_port); //组包 if(m_len>0){ QString str=QString("[%1:%2]:%3").arg(m_ip.toString()).arg(m_port).arg(array); array[m_len]='\0'; //设置文本区内容 p_sendBox->append(str); } } void WidgetA::sendData(){ //获取接收方的IP端口号 QString m_ip=p_ipEdit->text(); quint16 m_port=p_portEdit->text().toInt(); //获取文本区内 QString str=p_sendBox->toPlainText(); //往通信套接字中写数据 p_udpSocket->writeDatagram(str.toUtf8(),QHostAddress(m_ip),m_port); } void WidgetA::closeConnection(){ p_udpSocket->close(); } 复制代码另外两个窗口实现的方法类似。 //main.cpp #include "WidgetA.h" #include "WidgetB.h" #include "WidgetC.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); WidgetA wa; WidgetB wb; WidgetC wc; wa.show(); wb.show(); wc.show(); return a.exec(); } 复制代码实现效果:
|
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |