QT笔记——网络通信 之 QUdpSocket

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

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值