QUdpSocket-Qt使用Udp通讯实现服务端和客户端

版权声明:若无来源注明,Techie亮博客文章均为原创。 转载请以链接形式标明本文标题和地址:
本文标题:QUdpSocket-Qt使用Udp通讯实现服务端和客户端     本文地址:http://techieliang.com/2017/12/532/

摘自:https://www.cnblogs.com/techiel/p/7978049.html

https://blog.csdn.net/we1583004we/article/details/79188305

https://www.cnblogs.com/wurenzhong/p/8030220.html

文章目录

1. QNetworkDatagram

qt网络报文,可用其建立一个通讯内容包括目标ip、端口号、数据内容。同时接收到的信息也未此类型,可以访问接收数据的长度、发送者的ip及端口等信息

详情请见帮助

QUdpSocket

有Qt提供的udp通讯的类,详细介绍请见官方文档

2. 客户端

注意pro文件要包含QT += network

  1. #include <QHostAddress>
  2. #include <QUdpSocket>
  3. QUdpSocket *m_socket=new QUdpSocket;
  4. m_socket.writeDatagram(msg, QHostAddress::localhost, 8000);

qudpsocket对于发送数据报文提供了三个重载函数:

  1. qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)
  2. qint64 writeDatagram(const QNetworkDatagram &datagram)
  3. qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)

上面的范例使用的是第三种类型,也可以自行建立QNetworkDatagram对象,修改好内容后直接调用writeDatagram

3. 服务端

服务端与客户端类似,需要先绑定端口“bind”,此函数在QAbstractSocket类中提供

  1. bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform)
  2. bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform)

具体使用方式:

  1. m_socket = new QUdpSocket;
  2. m_socket->bind(QHostAddress::localhost, 8000);
  3. connect(m_socket, SIGNAL(readyRead()), this, SLOT(receive()));

绑定端口以后,需要将此socket的readyread信号与自定义槽函数连接,当服务端收到消息时会触发此信号。

4. 消息收发

由于udp与tcp不同,不需要三次握手建立连接,所以并不会在连接之后记录当前socket。

发送消息在客户端中已经提供示例

接收消息需要使用Qudpsocket提供以下函数:

  1. qint64 pendingDatagramSize() const
  2. qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)
  3. QNetworkDatagram receiveDatagram(qint64 maxSize = -1)

当readyRead信号触发时,可直接通过receiveDatagram函数获取消息报文对象,其内存储消息的发送ip、端口、消息内容等所有信息。

也可以通过pendingDatagramSize判断消息长度,然后通过readDatagram获取消息内容。

在readyRead槽函数中可以先调用QUdpSocket::hasPendingDatagrams判断当前是否有需要读取的消息,若有消息再进行pendingDatagramSize获取需要读取的大小

 

实例:

客户端

udpclient.cpp

 


 
  1. #include "udpclient.h"

  2. #include "ui_udpclient.h"

  3. #include <QTextCodec>

  4. #include <QDebug>

  5. UdpClient::UdpClient(QWidget *parent) :

  6. QMainWindow(parent),

  7. ui(new Ui::UdpClient)

  8. {

  9. ui->setupUi(this);

  10. //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

  11. clientudp=new QUdpSocket(this);

  12. clientudp->bind(6000,QUdpSocket::ShareAddress);//绑定读数据端口(监听端口),允许其他服务绑定到此端口

  13. connect(clientudp,SIGNAL(readyRead()),this,SLOT(recv()));

  14. }

  15.  
  16. UdpClient::~UdpClient()

  17. {

  18. delete ui;

  19. }

  20.  
  21. void UdpClient::on_pushButton_clicked()

  22. {

  23. // QHostAddress serverip;

  24. // serverip.setAddress(QString("192.168.0.7"));//这是人为指定ip地址的方法

  25. clientudp->writeDatagram(QVariant(ui->textEdit_write->toPlainText()).toByteArray(),QHostAddress::LocalHost,5000);//向5000端口写数据

  26. }

  27. void UdpClient::recv()

  28. {

  29. while(clientudp->hasPendingDatagrams())

  30. {

  31. QByteArray data;

  32. data.resize(clientudp->pendingDatagramSize());

  33. clientudp->readDatagram(data.data(),data.size());

  34. ui->textEdit_show->setText(QVariant(data).toString());

  35. }

  36. }

  37. //注意,监听与发送的端口可以相同也可以不同,它们相对独立,就像有名管道



服务端代码:

 

udpserver.cpp


 
  1. #include "udpserver.h"

  2. #include "ui_udpserver.h"

  3. #include <QVariant>

  4. UdpServer::UdpServer(QWidget *parent) :

  5. QMainWindow(parent),

  6. ui(new Ui::UdpServer)

  7. {

  8. ui->setupUi(this);

  9. serverudp=new QUdpSocket(this);

  10. serverudp->bind(5000,QUdpSocket::ShareAddress);//绑定读数据端口(监听端口),允许其他服务绑定到此端口

  11. connect(serverudp,SIGNAL(readyRead()),this,SLOT(recv()));

  12. }

  13.  
  14. UdpServer::~UdpServer()

  15. {

  16. delete ui;

  17. }

  18. void UdpServer::recv()

  19. {

  20. while(serverudp->hasPendingDatagrams())

  21. {

  22. QByteArray data;

  23. data.resize(serverudp->pendingDatagramSize());

  24. serverudp->readDatagram(data.data(),data.size());//

  25. ui->textEdit_show->clear();

  26. ui->textEdit_show->setText(QVariant(data).toString());

  27. }

  28. }

  29.  
  30. void UdpServer::on_pushButton_clicked()

  31. {

  32. // QHostAddress serverip;

  33. // serverip.setAddress(QString("192.168.0.7"));//这是人为指定ip地址的方法

  34. serverudp->writeDatagram(QVariant(ui->textEdit_write->toPlainText()).toByteArray(),QHostAddress::LocalHost,6000);//向6000端口写数据

  35. }

  36. //注意,监听与发送的端口可以相同也可以不同,它们相对独立,就像有名管道

执行结果:

代码下载链接:

点击打开链接

--------------------- 本文来自 小明37 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/we1583004we/article/details/79188305?utm_source=copy

 

这里说明一下,UDP通信中分为三种通信分别为单播、组播和广播,下面将一一为大家介绍。

同样的我们都需要在工程文件中添加network

QT       += core gui network

进行UDP通信需要用到的头文件

#include <QUdpSocket>

这里我们把UDP通信分为两个部分写,一个是发送端,另一个是接收端,而发送端中又分为单播、组播和广播三种形式,下面我们先来看看写发送端的代码程序的步骤:

发送端Udpsend的代码:

1、单播

   (1)创建套接字    

QUdpSocket mSocket;
mSocket = new QUdpSocket();

     (2)发送数据到指定的地址和端口号 

mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("192.168.137.1"),6677);
参数:ui->textEdit->toPlainText().toUtf8 要发送的消息
     QHostAddress("192.168.137.1")   接收端的ip地址
     6677  端口号,要和接收端的一致

 

2、组播,组播和单播的步骤是一样的,只有ip地址处有区别

组播ip地址范围:224.0.0.0-239.255.255.255
例子:mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("224.0.0.100"),6677);

 

3、广播,广播也只有ip地址和单播有区别

广播地址ip:QHostAddress::Broadcast
例子:mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress::Broadcast,6677);

好了,单播、组播和广播的区别应该都了解了,那么我们就来看发送端(udpsend.cpp)的具体代码:

复制代码

 1 #include "udpsend.h"
 2 #include "ui_udpsend.h"
 3 
 4  UdpSend:: UdpSend(QWidget *parent) :
 5     QMainWindow(parent),
 6     ui(new Ui:: UdpSend)
 7 {
 8     ui->setupUi(this);
 9 
10     //初始化创建QUdpSocket对象
11     mSocket = new QUdpSocket();
12 }
13 
14  UdpSend::~ UdpSend()
15 {
16     delete ui;
17 }
18 
19 void UdpSend::on_sendBt_clicked()
20 {
21     //单播
22    // qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("192.168.137.1"),6677);
23 
24 
25     //组播ip地址范围:224.0.0.0-239.255.255.255
26     //qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("224.0.0.100"),6677);
27 
28     //广播
29     qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress::Broadcast,6677);
30 
31 
32 }

复制代码

发送端的界面文件我做的很简单,我只做了发送消息框:

 

看完发送端的代码,我们继续来看接收端的代码(Udprecv)

接收端不管是单播、或者组播还是广播代码都是一样的,下面是写接收端代码的步骤:

1、创建套接字

QUdpSocket mSocket;
mSocket = new QUdpSocket();

2、绑定地址和端口号

mSocket->bind(QHostAddress::AnyIPv4,6677);
参数:AnyIPv4  IPv4
     6677  端口号,要和发送端的一致

3、等待数据的到来,利用readyRread()

connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));

4、读数据

复制代码

readDatagram(char * data, qint64 maxSize, QHostAddress * address = 0, quint16 * port = 0)
 参数:
      data:数据
      maxSize:数据的大小
      address:QHostAddress类型的地址
      port:端口号

例子:
void UdpRecv::read_data()
{
    QByteArray array;
    QHostAddress address;
    quint16 port;
    array.resize(mSocket->bytesAvailable());//根据可读数据来设置空间大小
    mSocket->readDatagram(array.data(),array.size(),&address,&port); //读取数据
    ui->listWidget->addItem(array);//显示数据
   //发送反馈数据

}

复制代码

如果是组播的话还涉及到加入组播和退出组播

加入到组播组  joinMulticastGroup
            例子:mSocket->joinMulticastGroup(QHostAddress("224.0.0.100"));

退出组播组    leaveMulticastGroup
            例子: mSocket->leaveMulticastGroup(QHostAddress("224.0.0.100"));

 

来看看接收端(Udprecv.cpp)具体实现的代码

复制代码

 1 #include "udprecv.h"
 2 #include "ui_udprecv.h"
 3 
 4 UdpRecv::UdpRecv(QWidget *parent) :
 5     QMainWindow(parent),
 6     ui(new Ui::UdpRecv)
 7 {
 8     ui->setupUi(this);
 9 
10     //创建对象 初始化
11     mSocket = new QUdpSocket();
12 
13     //绑定
14     mSocket->bind(QHostAddress::AnyIPv4,6677);
15     //关联读数据信号readyread
16     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
17 
18 }
19 
20 UdpRecv::~UdpRecv()
21 {
22     delete ui;
23 }
24 
25 void UdpRecv::read_data()
26 {
27     QByteArray array;
28     QHostAddress address;
29     quint16 port;
30     array.resize(mSocket->bytesAvailable());//根据可读数据来设置空间大小
31     mSocket->readDatagram(array.data(),array.size(),&address,&port); //读取数据
32     ui->listWidget->addItem(array);//显示数据
33    //发送反馈数据
34 
35 }
36 
37 void UdpRecv::on_checkBox_clicked(bool checked)
38 {
39     if(checked)
40     {
41         //加入组播
42         mSocket->joinMulticastGroup(QHostAddress("224.0.0.100"));
43     }
44 
45     else
46     {
47         //退出组播
48         mSocket->leaveMulticastGroup(QHostAddress("224.0.0.100"));
49 
50     }
51 
52 }

复制代码

接收端的界面文件我只加了显示接收到的信息和选择是否加入组播的选择按钮

 

这是发送端和接收分开来写的,此外我也实现了一下发送端和接收端写到同一个文件中

头文件qudpapp.h中的代码

复制代码

 1 #ifndef QUDPAPP_H
 2 #define QUDPAPP_H
 3 
 4 #include <QWidget>
 5 #include <QUdpSocket>
 6 namespace Ui {
 7 class QUdpApp;
 8 }
 9 
10 class QUdpApp : public QWidget
11 {
12     Q_OBJECT
13 
14 public:
15     explicit QUdpApp(QWidget *parent = 0);
16     ~QUdpApp();
17 
18 private slots:
19     void on_sendSigRb_clicked(); //单播旋转轴
20     void on_sendMulRb_clicked();  //组播选择
21     void on_sendBroadRb_clicked(); //广播选择
22     void on_sendBt_clicked(); //发送按钮
23 
24 //===========================================
25     void on_recvCb_clicked(bool checked);  //选择接收
26     void on_recvJoinMulBt_clicked();  //加入组播
27     void on_recvLeaveMulBt_clicked(); //退出组播
28 
29     void on_sendMesEdit_cursorPositionChanged();//检测消息框是否有数据
30     void read_data();
31 
32 private:
33     Ui::QUdpApp *ui;
34     QUdpSocket *mSocket;
35     QHostAddress sendaddrees;
36     QString sendPort;
37 
38 };
39 
40 #endif // QUDPAPP_H

复制代码

源文件qudpapp.cpp中的代码

复制代码

  1 #include "qudpapp.h"
  2 #include "ui_qudpapp.h"
  3 #include <QMessageBox>
  4 QUdpApp::QUdpApp(QWidget *parent) :
  5     QWidget(parent),
  6     ui(new Ui::QUdpApp)
  7 {
  8     ui->setupUi(this);
  9     mSocket = new QUdpSocket();//创建套接字
 10     ui->sendBt->setEnabled(false);
 11 }
 12 
 13 QUdpApp::~QUdpApp()
 14 {
 15     delete ui;
 16 }
 17 
 18 
 19 //==========================发送端====================
 20 //单播选择
 21 void QUdpApp::on_sendSigRb_clicked()
 22 {
 23     if(ui->sendPortEdit->text().isEmpty() || ui->sendSigAddrEdit->text().isEmpty())
 24     {
 25         QMessageBox::warning(this,"提示","请输入单播ip和端口号");
 26         //ui->sendSigRb->setChecked(false);
 27         return;
 28     }
 29     sendaddrees.setAddress( ui->sendSigAddrEdit->text());
 30     sendPort  = ui->sendPortEdit->text();
 31 
 32 }
 33 
 34 //组播选择
 35 void QUdpApp::on_sendMulRb_clicked()
 36 {
 37     if(ui->sendPortEdit->text().isEmpty() || ui->sendMulAddrEdit->text().isEmpty())
 38     {
 39         QMessageBox::warning(this,"提示","请输入组播ip和端口号");
 40         //ui->sendSigRb->setChecked(false);
 41         return;
 42     }
 43    sendaddrees.setAddress( ui->sendMulAddrEdit->text());
 44    sendPort  = ui->sendPortEdit->text();
 45 
 46 }
 47 
 48 //广播选择
 49 void QUdpApp::on_sendBroadRb_clicked()
 50 {
 51     if(ui->sendPortEdit->text().isEmpty() || ui->sendBroadAddrEdit->text().isEmpty())
 52     {
 53         QMessageBox::warning(this,"提示","请输入广播ip和端口号");
 54         //ui->sendSigRb->setChecked(false);
 55         return;
 56     }
 57     sendaddrees.setAddress( ui->sendBroadAddrEdit->text());
 58     sendPort  = ui->sendPortEdit->text();
 59 
 60 }
 61 
 62 //发送按钮
 63 void QUdpApp::on_sendBt_clicked()
 64 {
 65     mSocket->writeDatagram(ui->sendMesEdit->toPlainText().toUtf8(),sendaddrees,sendPort.toInt());
 66 
 67 }
 68 
 69 //检测发送消息对话框中是否有消息
 70 void QUdpApp::on_sendMesEdit_cursorPositionChanged()
 71 {
 72     if(ui->sendMesEdit->toPlainText().isEmpty())
 73     {
 74         ui->sendBt->setEnabled(false);
 75     }
 76     else
 77     {
 78         ui->sendBt->setEnabled(true);
 79     }
 80 
 81 }
 82 
 83 //==========================发送端====================
 84 
 85 
 86 //==========================接收端=====================
 87 
 88 //选择接收
 89 void QUdpApp::on_recvCb_clicked(bool checked)
 90 {
 91     if(ui->recvPortEdit->text().isEmpty())
 92     {
 93         QMessageBox::warning(this,"提示","请输入端口号");
 94         ui->recvCb->setChecked(false);
 95         return;
 96     }
 97     if(checked)
 98     {
 99         mSocket->bind(QHostAddress::AnyIPv4,ui->recvPortEdit->text().toInt());
100         connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
101         ui->recvPortEdit->setEnabled(false);
102     }
103     else
104     {
105         mSocket->close();
106         ui->recvPortEdit->setEnabled(true);
107     }
108 }
109 
110 //加入组播
111 void QUdpApp::on_recvJoinMulBt_clicked()
112 {
113     if(ui->recvMulAddrEdit->text().isEmpty())
114     {
115         QMessageBox::warning(this,"提示","请输入组播ip");
116         return;
117     }
118     if(mSocket->joinMulticastGroup(QHostAddress(ui->recvMulAddrEdit->text()))) //加入组播
119     {
120         ui->recvMulAddr->addItem(ui->recvMulAddrEdit->text());
121     }
122     else
123     {
124         QMessageBox::warning(this,"提示","加入组播失败,请修改ip后继续加入");
125         //return;
126     }
127 
128 }
129 
130 //退出组播
131 void QUdpApp::on_recvLeaveMulBt_clicked()
132 {
133     mSocket->leaveMulticastGroup(QHostAddress(ui->recvMulAddr->currentIndex()));//退出组播地址列表当前的组播
134     ui->recvMulAddr->removeItem(ui->recvMulAddr->currentIndex()); //删除组播地址列表中当前的组播地址
135 }
136 
137 void QUdpApp::read_data()
138 {
139     QByteArray array;
140     array.resize(mSocket->bytesAvailable()); //将接收数据的array设置成为要接收数据的大小
141     QHostAddress recvaddress;
142     quint16 port;
143     mSocket->readDatagram(array.data(),array.size(),&recvaddress,&port); //读取数据
144     ui->recvList->addItem(array);
145 
146 }
147 
148 //==========================接收端=====================

复制代码

界面文件qudpapp.ui

发布了6 篇原创文章 · 获赞 25 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览