• 3972阅读
  • 11回复

[提问]QT网络通信   UDP广播+多线程问题 [复制链接]

上一主题 下一主题
离线suzhuorui
 

只看楼主 倒序阅读 楼主  发表于: 2019-08-14
— 本帖被 圣域天子 从 Qt 作品展 移动到本区(2019-08-21) —
程序A中每次创建5个线程发送广播       但是程序B每次只能接收到2个。代码就是最简单的测试代码,求大佬告知问题所在


离线firebolt

只看该作者 1楼 发表于: 2019-08-14
不明白广播为啥要用5个线程,如果是测试多线程需要给udpSocket加个锁。
离线yunchao630

只看该作者 2楼 发表于: 2019-08-15
同上,发送广播的函数互斥一下
离线suzhuorui

只看该作者 3楼 发表于: 2019-08-15
回 firebolt 的帖子
firebolt:不明白广播为啥要用5个线程,如果是测试多线程需要给udpSocket加个锁。 (2019-08-14 22:09) 

加锁的话,我是在run函数中加的,也没用呀
如果我想让 for循环中的5个线程 依次发送广播,就是等待第一个线程发送完毕再开始第二个线程,要怎么办呢?
离线suzhuorui

只看该作者 4楼 发表于: 2019-08-15
回 suzhuorui 的帖子
suzhuorui:加锁的话,我是在run函数中加的,也没用呀
如果我想让 for循环中的5个线程 依次发送广播,就是等待第一个线程发送完毕再开始第二个线程,要怎么办呢? (2019-08-15 14:12) 

用计时器可以做到    但是用for循环怎么做呢?求大神指点
离线powerriver

只看该作者 5楼 发表于: 2019-08-20
使用信号/槽,不要使用循环的方式,在初始化时
    udpsocket = new QUdpSocket(this);
    bool ret = udpsocket->bind(port, QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
    if (!ret)
        exit(0);
    connect(udpsocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));

void Mainwindow::readPendingDatagrams()
{
    while(udpsocket->hasPendingDatagrams())
    {
     .....
离线suzhuorui

只看该作者 6楼 发表于: 2019-08-21
回 powerriver 的帖子
powerriver:使用信号/槽,不要使用循环的方式,在初始化时
    udpsocket = new QUdpSocket(this);
    bool ret = udpsocket->bind(port, QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
    if (!ret)
 &n .. (2019-08-20 22:52) 

我循环只是为了多开线程,而且我也有用到信号槽
我就是想测试一下这个广播,想看看一下子发送的人数多了(就是循环五次开了五个线程) ,   能不能全部接到,但结果是不能的,我也不知道问题出在哪里,所以.......大佬
离线青空飞羽

只看该作者 7楼 发表于: 2019-08-21
UdpSend中的udpSocket应该放在run方法里去new吧,这样udpSocket才是属于线程,放到构造函数里new的话还是属于主线程
离线suzhuorui

只看该作者 8楼 发表于: 2019-08-21
回 青空飞羽 的帖子
青空飞羽:
UdpSend中的udpSocket应该放在run方法里去new吧,这样udpSocket才是属于线程,放到构造函数里new的话还是属于主线程

青空飞羽:
UdpSend中的udpSocket应该放在run方法里去new吧,这样udpSocket才是属于线程,放到构造函数里new的话还是属于主线程

放进去了,但还是不可以。

我在run函数中加入了一个全局变量,并且加锁看了一下,现在的问题是在第一次点击发送广播按钮后只能接收到0和4,而接下来的每一次都能接收到5次正确的值,这是为什么呢?



离线suzhuorui

只看该作者 9楼 发表于: 2019-08-22
问题解决了,上完整的代码

发送端界面cpp
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <QUdpSocket>
  4. #include "udpsend.h"
  5. #include <QMutex>
  6. MainWindow::MainWindow(QWidget *parent) :
  7.     QMainWindow(parent),
  8.     ui(new Ui::MainWindow)
  9. {
  10.       ui->setupUi(this);
  11. }
  12. MainWindow::~MainWindow()
  13. {
  14.       delete ui;
  15. }
  16. int num=0;
  17. QMutex mutex;
  18. void MainWindow::on_pushButton_clicked()
  19. {
  20.       UdpSend *thread[5];
  21.       for(int i=0;i<5;i++)
  22.       {
  23.             mutex.lock();
  24.             qDebug()<<i;
  25.             thread[i]=new UdpSend();
  26.             connect(thread[i],SIGNAL(finished()),this,SLOT(deleteLater()));
  27.             thread[i]->start();
  28.       }
  29. }





发送端线程cpp    
UdpSend线程类
  1. [color=#000000]#include "udpsend.h"[/color]
  2. [color=#000000]#include <QMutex>[/color]
  3. [color=#000000]UdpSend::UdpSend(QObject *parent) : QThread(parent)[/color]
  4. [color=#000000]{[/color]
  5. [color=#000000]}[/color]
  6. [color=#000000]extern int num;[/color]
  7. [color=#000000]extern QMutex mutex;[/color]
  8. [color=#000000]void UdpSend::run()[/color]
  9. [color=#000000]{[/color]
  10. [color=#000000]    myUdpSocket=new QUdpSocket(this);[/color]
  11. [color=#000000]    QString data="广播"+QString::number(num);[/color]
  12. [color=#000000]    num++;[/color]
  13. [color=#000000]    myUdpSocket->writeDatagram(data.toUtf8(),QHostAddress::Broadcast,quint16(5555));[/color]
  14. [color=#000000]    mutex.unlock();[/color]
  15. [color=#000000]    exec();[/color]
  16. [color=#000000]}[/color]





接收端cpp


  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. MainWindow::MainWindow(QWidget *parent) :
  4.     QMainWindow(parent),
  5.     ui(new Ui::MainWindow)
  6. {
  7.       ui->setupUi(this);
  8.       udpsocket=new QUdpSocket(this);
  9.       udpsocket->bind(QHostAddress::AnyIPv4,quint16(5555));
  10.       connect(udpsocket,SIGNAL(readyRead()),this,SLOT(ricv_msg()));
  11. }
  12. MainWindow::~MainWindow()
  13. {
  14.       delete ui;
  15. }
  16. void MainWindow::ricv_msg()
  17. {
  18.       QHostAddress sendID;
  19.       quint16 sendport;
  20.       QByteArray data;
  21.       if(udpsocket->hasPendingDatagrams())
  22.       {
  23.             data.resize(udpsocket->pendingDatagramSize());
  24.             udpsocket->readDatagram(data.data(),data.size(),&sendID,&sendport);
  25.       }
  26.       QString str="发送端的IP:"+sendID.toString()+"  端口号:"+QString::number(sendport)+"  内容:"+data;
  27.       ui->textBrowser->append(str);
  28. }



总结一下
1.首先使用循环创建多线程时需要加锁
2.在接收端的接收函数不要使用while(udpsocket->hasPendingDatagrams()),而要用if(udpsocket->hasPendingDatagrams())
3.接收数据的大小不能用data.resize(udpsocket->bytesAvailable());,而要用data.resize(udpsocket->pendingDatagramSize());,否则可能会有接收大小不一致,会导致出现意外乱码

以上代码为我个人意见,若有问题请指出来共同进步
离线fsu0413

只看该作者 10楼 发表于: 2019-08-23
回 suzhuorui 的帖子
suzhuorui:问题解决了,上完整的代码
发送端界面cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
....... (2019-08-22 09:56) 

用if肯定是错的,应该用while,后面的处理应该放到while里
离线suzhuorui

只看该作者 11楼 发表于: 2019-08-23
回 fsu0413 的帖子
fsu0413:用if肯定是错的,应该用while,后面的处理应该放到while里 (2019-08-23 08:33) 

卧槽,我试了一下,果然可以。想了想if是只执行一次,while是可以接收一个用户的多个包。谢谢大佬指出错误
快速回复
限100 字节
 
上一个 下一个