UDP服务端界面(发送端)
UDP客户端(接收端)
UDP服务端
(1)在头文件“udpserver.h”中声明了需要的各种控件,其具体代码如下:
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
class UdpServer : public QDialog
{
Q_OBJECT
public:
UdpServer(QWidget *parent=0,Qt::WindowFlags f=0);
~UdpServer();
private:
QLabel *TimerLabel;
QLineEdit *TextLineEdit;
QPushButton *StartBtn;
QVBoxLayout *mainLayout;
};
(2)源文件“udpserver.cpp”的具体代码如下:
#include "udpserver.h"
UdpServer::UdpServer(QWidget *parent,Qt::WindowFlags f)
: QDialog(parent,f)
{
setWindowTitle(tr("UDP Server")); //设置窗体的标题
/* 初始化各个控件 */
TimerLabel = new QLabel(tr("计时器:"),this);
TextLineEdit = new QLineEdit(this);
StartBtn = new QPushButton(tr("开始"),this);
/* 设置布局 */
mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(TimerLabel);
mainLayout->addWidget(TextLineEdit);
mainLayout->addWidget(StartBtn);
}
UDP服务器具体操作步骤如下。
(1)在“UdpServer.pro”中添加如下语句:
QT += network
(2)在头文件“udpserver.h”中添加需要的槽函数,其具体代码如下:
#include <QUdpSocket>
#include <QTimer>
public slots:
void StartBtnClicked();
void timeout();
private:
int port;
bool isStarted;
QUdpSocket *udpSocket;
QTimer *timer;
(3)在源文件“udpserver.cpp”中添加声明:
#include
其中,在构造函数中添加如下代码:
connect(StartBtn,SIGNAL(clicked()),this,SLOT(StartBtnClicked()));
port = 5555; //设置UDP的端口号参数,服务器定时向此端口发送广播信息
isStarted = false;
udpSocket = new QUdpSocket(this);
timer = new QTimer(this); //创建一个QUdpSocket
//定时发送广播信息
connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
StartBtnClicked()函数的具体代码如下:
void UdpServer::StartBtnClicked()
{
if(!isStarted)
{
StartBtn->setText(tr("停止"));
timer->start(1000);
isStarted =true;
}
else
{
StartBtn->setText(tr("开始"));
isStarted = false;
timer->stop();
}
}
timeout()函数完成了向端口发送广播信息的功能,其具体代码如下:
void UdpServer::timeout()
{
QString msg = TextLineEdit->text();
int length=0;
if(msg=="")
{
return;
}
if((length=udpSocket->writeDatagram(msg.toLatin1(),
msg.length(),QHostAddress::Broadcast,port))!=msg.length())
{
return;
}
}
UDP客户端编程
(1)在头文件“udpclient.h”中声明了需要的各种控件,其具体代码如下:
#include <QDialog>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QPushButton>
class UdpClient : public QDialog
{
Q_OBJECT
public:
UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
~UdpClient();
private:
QTextEdit *ReceiveTextEdit;
QPushButton *CloseBtn;
QVBoxLayout *mainLayout;
};
(2)源文件“udpclient.cpp”的具体代码如下:
#include "udpclient.h"
UdpClient::UdpClient(QWidget *parent, Qt::WindowFlags f)
: QDialog(parent,f)
{
setWindowTitle(tr("UDP Client")); //设置窗体的标题
/* 初始化各个控件 */
ReceiveTextEdit = new QTextEdit(this);
CloseBtn = new QPushButton(tr("Close"),this);
/* 设置布局 */
mainLayout=new QVBoxLayout(this);
mainLayout->addWidget(ReceiveTextEdit);
mainLayout->addWidget(CloseBtn);
}
以上只是完成了客户端界面的实现,下面完成它的数据接收和显示的功能。
操作步骤如下。
(1)在“UdpClient.pro”中添加如下语句:
QT += network
(2)在头文件“udpclient.h”中添加如下代码:
#include <QUdpSocket>
public slots:
void CloseBtnClicked();
void dataReceived();
private:
int port;
QUdpSocket *udpSocket;
(3)在源文件“udpclient.cpp”中添加如下声明:
#include <QMessageBox>
#include <QHostAddress>
其中,在构造函数中添加的代码如下:
connect(CloseBtn,SIGNAL(clicked()),this,SLOT(CloseBtnClicked()));
port =5555; //设置UDP的端口号参数,指定在此端口上监听数据
udpSocket = new QUdpSocket(this); //创建一个QUdpSocket
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived())); //(a)
bool result=udpSocket->bind(port); //绑定到指定的端口上
if(!result)
{
QMessageBox::information(this,tr("error"),tr("udp socket create error!"));
return;
}
CloseBtnClicked()函数的具体内容如下:
void UdpClient::CloseBtnClicked()
{
close();
}
dataReceived()函数响应QUdpSocket的readyRead()信号,一旦UdpSocket对象中有数据可读时,即通过readDatagram()方法将数据读出并显示。其具体代码如下:
void UdpClient::dataReceived()
{
while(udpSocket->hasPendingDatagrams()) //(a)
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(),datagram.size()); //(b)
QString msg=datagram.data();
ReceiveTextEdit->insertPlainText(msg); //显示数据内容
}
}
同时运行UdpServer与UdpClient工程,首先在服务器界面的文本框中输入“hello!”,然后单击“开始”按钮,按钮文本变为“停止”,客户端就开始不断地收到“hello!”字符消息并显示在文本区,当单击服务器的“停止”按钮后,按钮文本又变回“开始”,客户端也就停止了字符的显示,再次单击服务器的“开始”按钮,客户端又继续接收并显示……如此循环往复。
但是如果传送的信息是中文,则会出现一段问号:
中文乱码的解决办法
- 发送端将要发送的字符串转成UTF-8的格式
- 接收端将UTF-8的数据转成字符串
发送端
写报文的函数原型:
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) //(1)
qint64 writeDatagram(const QNetworkDatagram &datagram)//(2)
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)//(3)
在使用第一个函数原型时,要特别注意size是编码后数据的长度,也就是data的长度,而不是原始数据的长度。
将原始的写报文代码:
if((length=udpSocket->writeDatagram(msg.toLatin1(),
msg.length(),QHostAddress::Broadcast,port))!=msg.length())
{
return;
}
改成
if(
(length = udpSocket->writeDatagram (msg.toUtf8 ().data(), msg.toUtf8().size(),
QHostAddress::Broadcast,port))!= msg.length ()
)
{
return ;
}
使用第三个函数原型:
/*发送数据
* 第一个参数:要发送的内容,这里是要发送输入框的内容,
* 参数没有QString类型,需要转换为QByteArray类型或Char*类型
* 第二个参数:要发送到的目标IP地址,这里是本机测试,所以用LocalHost
* 第三个参数:要发送的的目标端口,自己随意指定
* 返回值:发送成功返回发送的字节数,失败返回-1
*/
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
将原始的写报文代码改成:
if((length =
udpSocket->writeDatagram (msg.toUtf8 (),QHostAddress::Broadcast,port))
!= msg.length ())
{
return ;
}
接收端
读报文的函数原型:
qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)
将读报文的代码:
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(),datagram.size()); //(b)
QString msg=datagram.data();
ReceiveTextEdit->insertPlainText(msg); //显示数据内容
改成:
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(),datagram.size()); //(b)
//将utf-8的数据转成字符串
QString msg=QString::fromUtf8 (datagram.data ());
ReceiveTextEdit->insertPlainText(msg); //显示数据内容
最后效果: