在之前的qt控制台程序udp编程中始终面临着一个问题,就是socket的readRead信号绑定了类中的某个接收函数,但是始终不会被自动触发,只能通过手动进行触发,因为不知道何时会接收到消息,所以手动触发的方法不可取。分析之后,可能由于下面三种问题引起的不能触发:
- socket的构造方法不对
- main函数启动的顺序不对
- 焦点问题
经过几天的尝试,发现是由第三种情况引起的,因为主线程要担负发送和接受的任务,而发送任务是通过循环实现的,不断地监听控制台的输入,输入一行,发送一行。这样就造成了程序的焦点始终是在发送函数上,就算socket的信号发射,主线程也不会调用相应的接收函数。解决的方法就在于将socket的发送和接收端分开,给发送单独建立一个线程,怎样建立线程见另一篇博文:https://blog.csdn.net/mujiangyao/article/details/80917039。
下面代码是通过一个小的聊天程序说明原理。
//client1的主函数
#include <QtCore/QCoreApplication>
#include<client1.h>
#include<windows.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
client1 test;
return a.exec();
}
//client1的函数声明和实现
#pragma once
#include<QObject>
#include<QtNetwork/QUdpSocket>
#include<iostream>
#include<string>
#include<cstring>
#include<windows.h>
using namespace std;
class client1:public QObject
{
Q_OBJECT
public:
client1(QObject * parent = NULL);
static DWORD WINAPI send(void *);
HANDLE revSend;
~client1();
QUdpSocket *udpSocket;
private slots:
void rev();
};
//+++++++++++++++++++++++++++++++实现+++++++++++++++++++++++++++++++++++++++
#include "client1.h"
client1::client1(QObject * parent):QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(port, QUdpSocket::ShareAddress);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(rev()));
CreateThread(NULL, 0, send, (void *)this, 0, NULL);
}
DWORD WINAPI client1::send(void * __this)
{
client1 * _this = (client1 *)__this;
while (1)
{
QByteArray senddata;
string commandTmp = "";
getline(cin, commandTmp);
senddata.append(commandTmp.data(), commandTmp.size());
_this->udpSocket->writeDatagram(senddata, QHostAddress(ip), port);
}
}
void client1::rev()
{
while (udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
for (int i = 0; i < datagram.size(); i++)
{
printf("%c", datagram.at(i));
}
printf("\n");
}
}
client1::~client1()
{
delete(udpSocket);
}
client2的代码与client1的相似,ip和port可以自己自由设置,可以实现通信即可。