UDP(用户数据报协议),是一个轻量的,不可靠的,面向数据报的,非连接的协议。当通讯要求的可靠性不重要时(可能数据会丢失),可以用UDP通信
.pro文件中添加网络模块 QT += network
头文件:#include<QUdpSocket>
重要函数:
bind() //服务器绑定端口
hasPendingDatagrams() //当数据发来时,至少有一个数据报需要读取。
writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) //函数向指定的地址host和端口port发送数据报datagram,返回成功发送的字节数,数据报不要太长,不要超过512Byte
readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)
pendingDatagramSize() //函数第一个待读取的数据报的大小Byte。
joinMulticastGroup() //函数使socket加入一个多播组groupAddress。
leaveMulticastGroup() //函数使socket离开多播组groupAddress。
设计一下UI:
服务器:
1.绑定端口
m_udpSocket->bind(QHostAddress::AnyIPv4,8888);
2.发送消息 和 读取消息
2.1发送消息
//获取信息
QString sendStr = ui.sendTextEdit->toPlainText();
quint16 port = ui.portLineEdit->text().toInt();
QString ip = ui.IPlineEdit->text();
m_udpSocket->writeDatagram(sendStr.toUtf8(), QHostAddress(ip), port);
//连接socket 读取发送过来消息
connect(m_udpSocket, &QUdpSocket::readyRead, this, &QUdpTest::readValue);
2.2读取消息
while (m_udpSocket->hasPendingDatagrams())
{
QByteArray array;
//array.resize(m_udpSocket->bytesAvailable());
array.resize(m_udpSocket->pendingDatagramSize());
QHostAddress address;
quint16 port;
m_udpSocket->readDatagram(array.data(), array.size(),&address,&port);
qDebug() << QStringLiteral("传过来的大小为:") << array.size();
//用读取数据流
//QDataStream read(&array, QIODevice::ReadOnly);
//Person p;
//read >> p.age >> p.score ;
//read.readRawData(p.name, sizeof(p.name));
//QString str = QString("%1 %2 %3").arg(QString::number(p.age)).arg(p.name).arg(QString::number(p.score));
qDebug() << array.data();
//读取发来的结构体(强转为我们需要转化的结构体)
Person* p = reinterpret_cast<Person*>(array.data());
QString str1 = QString(QLatin1String(p->name));
QString str = QString("%1 %2 %3").arg(QString::number(p->age)).arg(str1).arg(QString::number(p->score));
ui.recvTextEdit->setText(str);
}
客户端:
1.绑定端口
m_socket->bind(QHostAddress::AnyIPv4,9999);
2.发送消息 和 读取消息
2.1发送消息
quint16 port = ui.portLineEdit->text().toInt();
QString ip = ui.IPLineEdit->text();
QString sendStr = ui.sendTextEdit->toPlainText();
Person p1;
strcpy(p1.name, "xm");
p1.age = 20;
p1.score = 60;
//发送数据流
//QByteArray text_data;
//QDataStream write(&text_data, QIODevice::WriteOnly);
//write << p1.age << p1.score ;
//write.writeRawData(p1.name, 20);
//m_socket->writeDatagram(text_data, text_data.size(), QHostAddress(ip), port);
//发送输入框中的内容
//m_socket->writeDatagram(sendStr.toUtf8(),QHostAddress(ip), port);
//m_socket->writeDatagram(sendStr.toLocal8Bit(), sendStr.size(), QHostAddress(ip), port);
//发送结构体
m_socket->writeDatagram(( char*)&p1, sizeof(Person), QHostAddress(ip), port);
qDebug() << QStringLiteral("发送的数据大小:") << sizeof(p1);
2.2读取消息
while (m_socket->hasPendingDatagrams())
{
QByteArray array;
//array.resize(m_socket->bytesAvailable());//根据可读数据来设置空间大小
array.resize(m_socket->pendingDatagramSize());
QHostAddress address;
quint16 port;
m_socket->readDatagram(array.data(), array.size(), &address, &port);
//显示中文不会乱码
ui.recvTextEdit->setText(QString::fromLocal8Bit(array.data()) );
}
3.客户端和服务端都加入组播
UDP组播是主机间一对一组的通信模式,当多个客户端加入由一个组播地址定义的多播组后,客户端向这个组播地址和端口发送的UDP数据报,组内成员都可以接收到。
m_socket->joinMulticastGroup(QHostAddress("224.0.0.100"));
完整代码:
QUdpTest.h
#pragma once
#include <QtWidgets/QWidget>
#include "ui_QUdpTest.h"
#include <QUdpSocket>
#include <QDebug>
class QUdpTest : public QWidget
{
Q_OBJECT
struct Person
{
char name[20];
int age;
int score;
Person()
{
memset(name, 0, 20);
age = 0;
score = 0;
}
};
public:
QUdpTest(QWidget *parent = Q_NULLPTR);
~QUdpTest();
public slots:
void readValue();
void on_sendBtn_clicked();
void on_delBtn_clicked();
private:
Ui::QUdpTestClass ui;
QUdpSocket* m_udpSocket;
};
QUdpTest.cpp
#include "QUdpTest.h"
#include <QDebug>
#include <QByteArray>
#include <QString>
#include <QLatin1String>
QUdpTest::QUdpTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
m_udpSocket = new QUdpSocket(this);
this->setWindowTitle(QStringLiteral("绑定端口号为:8888"));
//绑定端口
m_udpSocket->bind(QHostAddress::AnyIPv4,8888);
m_udpSocket->joinMulticastGroup(QHostAddress("224.0.0.100"));
connect(m_udpSocket, &QUdpSocket::readyRead, this, &QUdpTest::readValue);
ui.recvTextEdit->setReadOnly(true);
}
QUdpTest::~QUdpTest()
{
}
void QUdpTest::readValue()
{
while (m_udpSocket->hasPendingDatagrams())
{
QByteArray array;
//array.resize(m_udpSocket->bytesAvailable());
array.resize(m_udpSocket->pendingDatagramSize());
QHostAddress address;
quint16 port;
m_udpSocket->readDatagram(array.data(), array.size(),&address,&port);
qDebug() << QStringLiteral("传过来的大小为:") << array.size();
//QDataStream read(&array, QIODevice::ReadOnly); //读取数据流
//Person p;
//read >> p.age >> p.score ;
//read.readRawData(p.name, sizeof(p.name));
//QString str = QString("%1 %2 %3").arg(QString::number(p.age)).arg(p.name).arg(QString::number(p.score));
qDebug() << array.data();
Person* p = reinterpret_cast<Person*>(array.data());
QString str1 = QString(QLatin1String(p->name));
QString str = QString("%1 %2 %3").arg(QString::number(p->age)).arg(str1).arg(QString::number(p->score));
ui.recvTextEdit->setText(str);
}
}
void QUdpTest::on_sendBtn_clicked()
{
//获取信息
QString sendStr = ui.sendTextEdit->toPlainText();
quint16 port = ui.portLineEdit->text().toInt();
QString ip = ui.IPlineEdit->text();
m_udpSocket->writeDatagram(sendStr.toUtf8(), QHostAddress(ip), port);
}
void QUdpTest::on_delBtn_clicked()
{
m_udpSocket->leaveMulticastGroup(QHostAddress("224.0.0.100"));
}
QUdpTest1.h
#pragma once
#include <QWidget>
#include "ui_QUdpTest1.h"
#include <QUdpSocket>
class QUdpTest1 : public QWidget
{
Q_OBJECT
struct Person
{
char name[20];
int age;
int score;
Person()
{
memset(name, 0, 20);
age = 0;
score = 0;
}
};
public:
QUdpTest1(QWidget *parent = Q_NULLPTR);
~QUdpTest1();
public slots:
void readValue();
void on_sendBtn_clicked();
void on_delBtn_clicked();
private:
Ui::QUdpTest1 ui;
QUdpSocket* m_socket;
};
QUdpTest1.cpp
#include "QUdpTest1.h"
#include <string.h>
QUdpTest1::QUdpTest1(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
m_socket = new QUdpSocket(this);
this->setWindowTitle(QStringLiteral("绑定端口为:9999"));
m_socket->bind(QHostAddress::AnyIPv4,9999);
m_socket->joinMulticastGroup(QHostAddress("224.0.0.100"));
connect(m_socket, &QUdpSocket::readyRead, this, &QUdpTest1::readValue);
ui.recvTextEdit->setReadOnly(true);
}
QUdpTest1::~QUdpTest1()
{
}
void QUdpTest1::readValue()
{
while (m_socket->hasPendingDatagrams())
{
QByteArray array;
//array.resize(m_socket->bytesAvailable());//根据可读数据来设置空间大小
array.resize(m_socket->pendingDatagramSize());
QHostAddress address;
quint16 port;
m_socket->readDatagram(array.data(), array.size(), &address, &port);
ui.recvTextEdit->setText(array);
}
}
void QUdpTest1::on_sendBtn_clicked()
{
quint16 port = ui.portLineEdit->text().toInt();
QString ip = ui.IPLineEdit->text();
QString sendStr = ui.sendTextEdit->toPlainText();
Person p1;
strcpy(p1.name, "xm");
p1.age = 20;
p1.score = 60;
//QByteArray text_data;
//QDataStream write(&text_data, QIODevice::WriteOnly);
//write<< p1.age << p1.score ;
//write.writeRawData(p1.name, sizeof(p1.name));
//m_socket->writeDatagram(text_data, text_data.size(), QHostAddress(ip), port);
//m_socket->writeDatagram(sendStr.toUtf8(),QHostAddress(ip), port);
//m_socket->writeDatagram(sendStr.toLocal8Bit(), sendStr.size(), QHostAddress(ip), port);
m_socket->writeDatagram(( char*)&p1, sizeof(Person), QHostAddress(ip), port);
qDebug() << QStringLiteral("发送的数据大小:") << sizeof(p1);
}
void QUdpTest1::on_delBtn_clicked()
{
m_socket->leaveMulticastGroup(QHostAddress("224.0.0.100"));
}
运行结果:
发送文本中的内容:
发送结构体中的内容:
参考博客:
QT网络编程之UDP