使用Qt - udp通信方式,构建局域网聊天通信软件实例

  • 1.简介效果
  • 2.项目设计
    • 1)流程图
    • 2)项目构建
    • 3)界面构建
    • 4)代码设计
      • a.widget.h
      • b.widget.cpp
      • c.secondwidget.h
      • d.secondwidget.cpp
  • 3.源代码
    • widget.h
    • widget.cpp
    • secondwidget.h
    • secondwidget.cpp
  • 5.源文件下载

1.简介效果

在之前的文章中,介绍了TCP协议在Qt中的应用实现方式传送门,TCP通信方式是面向对象,可靠的连接服务。而与之对应的是不可靠,无连接的UDP通信协议,两者是TCP/IP协议簇中较为常用的两者通信方式。

之前的博文中,实现了利用Qt调用TCP协议的局域网通信聊天,而这篇博文将介绍UDP协议在Qt中的简单运用,其想要达到的效果如下。

使用UDP就和TCP不同的是,UDP协议只管发,实用于及时通信领域,它只管发送,不管对方是否收到,但因为其传输效率高效,消耗资源小,所以尝尝结合于TCP协议一同使用在通信连接中。我们最常用的就是QQ,QQ采用TCP连接来保持在线状态,使其连接至上层的腾讯服务器,而聊天发送消息功能大都采用UDP方式,当UDP协议不能正常转发的时候,就会采用TCP协议进行发送,所以,TCP和UDP协议常常一同使用。

2.项目设计

1)流程图

UDP协议流程图,如下图所示,经此流程图后,我们可以清晰的知道,UDP是如何通信工作,并进行调用。

UDP协议没有明确的客户端和服务端可言,只要绑定了对应的IP地址和端口号,就可以进行通信,如很多的组播软件,可以使绑定同一个IP。使得多个端口号的客户在此IP下进行通信和数据传输。

2)项目构建

新建为widget项目,构建如下所示项目树

3)界面构建

两个界面设计构建如下

  • 界面一 - secondwdiget

  • 界面二 - widget


使用行编辑框和文本编辑框构建简单的界面如上所示。

4)代码设计

和Qt使用TCP一样,想要在Qt中使用网络编程的包。需要在.pro工程文件里面添加如下代码

QT       += network

a.widget.h

首先还是需要添加Qt中封装好的UDP的头文件

#include <QUdpSocket>

之后对其进行初始化声明,并定义一个处理消息队列的槽函数,用以在UDP通信套接字连接后发送消息,之后便是重写事件过滤器用以响应键盘Enter键的输入,具体代码如下

public:void dealMsg();         //槽函数,处理对方发过来的数据
protected:bool eventFilter(QObject *target, QEvent *event);//事件过滤器
private:QUdpSocket *udpSocket;

b.widget.cpp

在执行文件中,对构建函数中的udpSocket分配动态空间,当连接好之后,自动并触发连接的槽函数。

Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);this->resize(450,300);this->setWindowTitle("服务器端口:8888");udpSocket = new QUdpSocket(this);//绑定端口号udpSocket->bind(8888);//udpSocket->bind(QHostAddress::AnyIPv4,8888);        //必须是主机的ipv4类通信方式,以及本机的ip地址//当对方发送数据过来。自动触发readyRead()connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);//键盘Enter键设置ui->ButtonSend->setFocus();ui->ButtonSend->setDefault(true);ui->textEditShow->installEventFilter(this);//设置完后自动调用其eventFilter函数}

之后便是对自定义处理消息队列的槽函数进行函数实现

void Widget::dealMsg()
{//读取对方发送的内容char buf[1024] = {0};           //内容QHostAddress cliAddr;           //对方地址quint16 port;                   //对方端口qint64 len = udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);//添加时间QTime cur_time = QTime::currentTime();QString time_info = cur_time.toString("hh:mm:ss");if(len >0){//获取到文本格式化 如 [192.168.1.1 : 8888]aaaa 的格式QString str = QString("[%1:%2] %3 [%4]").arg(cliAddr.toString()).arg(port).arg(buf).arg(time_info);//ui->textEditShow->setText(str);ui->textEditShow->append(str);}}

然后便是对事件过滤器的函数实现

bool Widget::eventFilter(QObject *target, QEvent *event)
{if(target == ui->textEditShow) //对象为需要发送的焦点{if(event->type() == QEvent::KeyPress)//回车键{QKeyEvent *k = static_cast<QKeyEvent *>(event);if(k->key() == Qt::Key_Return){on_ButtonSend_clicked();return true;}}}return QWidget::eventFilter(target,event);
}

最后是点击发送按钮,获取编辑框中的内容,使用通信套接字,将其发送给绑定特定端口号的一方

void Widget::on_ButtonSend_clicked()
{//获取对方的ip和端口QString ip = ui->lineEditIp->text();qint16 port = ui->lineEditPort->text().toInt();//获取编辑区内容QString str = ui->textEditShow->toPlainText();//给指定的ip发送数据udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);ui->textEditShow->clear();}

c.secondwidget.h

添加socket头文件方法和声明,以及消息队列处理函数,和键盘响应函数同上

public:void dealMsg2();         //槽函数,处理对方发过来的数据
protected:bool eventFilter(QObject *target, QEvent *event);//事件过滤器
private:QUdpSocket *udpSocket;

d.secondwidget.cpp

构造函数和第一个界面有一点点不同,如下

SecondWidget::SecondWidget(QWidget *parent) :QWidget(parent),ui(new Ui::SecondWidget)
{ui->setupUi(this);this->resize(450,300);this->setWindowTitle("服务器端口2:9999");udpSocket2 = new QUdpSocket(this);//绑定udpSocket2->bind(9999);connect(udpSocket2,&QUdpSocket::readyRead,this,&SecondWidget::dealMsg2);ui->ButtonSend2->setFocus();ui->ButtonSend2->setDefault(true);//ui->ButtonSend->setShortcut(Qt::Key_Enter|Qt::Key_Return);ui->textEditShow2->installEventFilter(this);//设置完后自动调用其eventFilter函数
}

其他的函数实现方式和第一个界面相同,这类不再赘述。待正确编译之后,即可实现这样的效果

  • 注意:Qt中UDP通信只需要在同一个ip下(需要绑定自己电脑上的ip,使用ipconfig命令查看该电脑的ipv4的地址),绑定对应的端口号。即可进行通信连接

3.源代码

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>namespace Ui {class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();void dealMsg();         //槽函数,处理对方发过来的数据
protected:bool eventFilter(QObject *target, QEvent *event);//事件过滤器private slots:void on_ButtonSend_clicked();void on_ButtonClose_clicked();private:Ui::Widget *ui;private:QUdpSocket *udpSocket;
};#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QHostAddress>
#include <QDebug>
#include <QTime>
#include <QKeyEvent>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);this->resize(450,300);this->setWindowTitle("服务器端口:8888");udpSocket = new QUdpSocket(this);//绑定端口号udpSocket->bind(8888);//udpSocket->bind(QHostAddress::AnyIPv4,8888);        //必须是主机的ipv4类通信方式,以及本机的ip地址//当对方发送数据过来。自动触发readyRead()connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);ui->ButtonSend->setFocus();ui->ButtonSend->setDefault(true);ui->textEditShow->installEventFilter(this);//设置完后自动调用其eventFilter函数}Widget::~Widget()
{delete ui;
}void Widget::dealMsg()
{//读取对方发送的内容char buf[1024] = {0};           //内容QHostAddress cliAddr;           //对方地址quint16 port;                   //对方端口qint64 len = udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);QTime cur_time = QTime::currentTime();QString time_info = cur_time.toString("hh:mm:ss");if(len >0){//获取到文本格式化  [192.168.1.1 : 8888]aaaaQString str = QString("[%1:%2] %3 [%4]").arg(cliAddr.toString()).arg(port).arg(buf).arg(time_info);//ui->textEditShow->setText(str);ui->textEditShow->append(str);}}bool Widget::eventFilter(QObject *target, QEvent *event)
{if(target == ui->textEditShow){if(event->type() == QEvent::KeyPress)//回车键{QKeyEvent *k = static_cast<QKeyEvent *>(event);if(k->key() == Qt::Key_Return){on_ButtonSend_clicked();return true;}}}return QWidget::eventFilter(target,event);
}void Widget::on_ButtonSend_clicked()
{//获取对方的ip和端口QString ip = ui->lineEditIp->text();qint16 port = ui->lineEditPort->text().toInt();//获取编辑区内容QString str = ui->textEditShow->toPlainText();//给指定的ip发送数据udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);ui->textEditShow->clear();}void Widget::on_ButtonClose_clicked()
{udpSocket->disconnectFromHost();udpSocket->close();qDebug() << "主服务器连接断开!";this->close();}

secondwidget.h

#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H#include <QWidget>
#include <QUdpSocket>namespace Ui {class SecondWidget;
}class SecondWidget : public QWidget
{Q_OBJECTpublic:explicit SecondWidget(QWidget *parent = nullptr);~SecondWidget();void dealMsg2();            //消息队列处理
protected:bool eventFilter(QObject *target, QEvent *event);//事件过滤器private slots:void on_ButtonSend2_clicked();void on_ButtonClose2_clicked();private:Ui::SecondWidget *ui;
private:QUdpSocket *udpSocket2;};#endif // SECONDWIDGET_H

secondwidget.cpp

#include "secondwidget.h"
#include "ui_secondwidget.h"
#include <QHostAddress>
#include <QDebug>
#include <QTime>
#include <QKeyEvent>SecondWidget::SecondWidget(QWidget *parent) :QWidget(parent),ui(new Ui::SecondWidget)
{ui->setupUi(this);this->resize(450,300);this->setWindowTitle("服务器端口2:9999");udpSocket2 = new QUdpSocket(this);//绑定udpSocket2->bind(9999);connect(udpSocket2,&QUdpSocket::readyRead,this,&SecondWidget::dealMsg2);ui->ButtonSend2->setFocus();ui->ButtonSend2->setDefault(true);//ui->ButtonSend->setShortcut(Qt::Key_Enter|Qt::Key_Return);ui->textEditShow2->installEventFilter(this);//设置完后自动调用其eventFilter函数
}SecondWidget::~SecondWidget()
{delete ui;
}void SecondWidget::dealMsg2()
{//读取对方发送的内容char buf[1024] = {0};           //内容QHostAddress cliAddr;           //对方地址quint16 port;                   //对方端口qint64 len = udpSocket2->readDatagram(buf,sizeof(buf),&cliAddr,&port);QTime cur_time = QTime::currentTime();QString time_info = cur_time.toString("hh:mm:ss");if(len >0){//获取到文本格式化  [192.68.1.144 : 8888]aaaaQString str = QString("[%1:%2] %3 [%4]").arg(cliAddr.toString()).arg(port).arg(buf).arg(time_info);//ui->textEditShow2->setText(str);ui->textEditShow2->append(str);}
}bool SecondWidget::eventFilter(QObject *target, QEvent *event)
{if(target == ui->textEditShow2){if(event->type() == QEvent::KeyPress)//回车键{QKeyEvent *k = static_cast<QKeyEvent *>(event);if(k->key() == Qt::Key_Return){on_ButtonSend2_clicked();return true;}}}return QWidget::eventFilter(target,event);
}void SecondWidget::on_ButtonSend2_clicked()
{//获取对方的ip和端口QString ip = ui->lineEditIp2->text();qint16 port = ui->lineEditPort2->text().toInt();//获取编辑区内容QString str = ui->textEditShow2->toPlainText();//给指定的ip发送数据udpSocket2->writeDatagram(str.toUtf8(),QHostAddress(ip),port);ui->textEditShow2->clear();
}void SecondWidget::on_ButtonClose2_clicked()
{udpSocket2->disconnectFromHost();udpSocket2->close();qDebug() << "断开连接!";this->close();}

5.源文件下载

如果感兴趣想要源文件的,请移至传送门源代码文件下载

QT -- UdpSocket通信实例,使用Qt的UDP通信协议,实现局域网组播通信软件功能相关推荐

  1. 网络编程-Socket套接字(TCP、UDP、广播和组播通信)

    socket套接字 socket是一个编程接口(网络编程接口) 作用是用来实现网络上不同的主机的应用进程之间进行双向通信 套接字是一种特殊的文件描述符 也就意味着我们使用套接字实现网络通信的时候可以用 ...

  2. linux UDP实现广播和组播

    广播 广播很简单,原理不解释了,这里实现的重点在于: 1.对服务器端的套接字使用setsockopt函数开放广播权限 2.指定要发送的IP(广播地址)+端口号 3.客户端必须显式绑定端口号(和2的端口 ...

  3. 基于UDP的多播(组播)文件传输

    此次的课程设计通过借鉴网上的信息(前人种树后人乘凉,感谢在网上分享的大佬们)然后自己再次修改调试完成. 步入正题吧 主要代码: public class MULTICAST {private Stri ...

  4. 浅谈 Qt 中 UDP 之 UdpSocket通信实例

    浅谈 Qt 中 UDP  写这篇博客的原因是Java大作业最近完成了一个简单的聊天室.也是基于UDP的.正好我们在学习Qt.所以我想能不能再qt中同样实现这样一个问题.于是我进行的代码的编辑.以及其他 ...

  5. java网络编程 UDP通信协议实现局域网内文件的发送和接收

    要实现两台内网下的机子进行通信,首先得知道接收方的内网IP,获取IP的方式:可以打开任务管理器的以太网进行查看: 如下 也可以通过 win+r 输入cmd ,然后输入 ipconfig  回车  进行 ...

  6. Qt udp组播Qt udp组播

    代码部分: #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QLabel> ...

  7. c#Socket通信实例

    一.Socket通信简介 1.按惯例先来介绍下socket Windows中的很多东西都是从Unix领域借鉴过来的,Socket也是一样.在Unix中,socket代表了一种文件描述符(在Unix中一 ...

  8. 虚拟机无法接受组播消息_基于UDP的组播通信

    基于UDP的组播通信 在Java实现基于UDP协议的发送端与接收端通信中,我们可以知道它的一些主要操作: 在发送端:1,创建绑定指定端口的发送接口:DatagramSocket(port) 2,创建绑 ...

  9. [转]UDP(udp通信、广播、组播),本地套接字

    转发参考链接: [陈宸-研究僧] https://blog.csdn.net/qq_35883464/article/details/103741461 [Alliswell_WP] https:// ...

  10. c/c++:UDP(udp通信、广播、组播),本地套接字

    目录 1. udp 1.1 udp通信流程 1.2 操作函数 send.sendto recv.recvfrom 2. 广播 2.1 广播通信流程 2.2 设置广播属性函数:setsockopt 2. ...

最新文章

  1. java简介 ppt 精_《JAVA》5选择结构精篇课件.ppt
  2. embedding层和全连接层的区别是什么 一般说embedding层,实现方式就是一个没有bias的fc层
  3. ECharts简单入门demo
  4. 德意志银行CEO:将逐渐用 AI 替代人工,银行决不会一成不变 凤凰科技 09-08 20:41 原标题:德意志银行CEO:将逐渐用 AI 替代人工,银行决不会一成不变 雷锋网AI金融评论报道,外媒i
  5. 操作系统:分享10个经常用的cmd命令
  6. java bufferarray_Java中的ByteBuffer array()方法
  7. python动态方法_python中的动态方法生成
  8. 因为一次宕机,终于搞透了 Kafka 高可用原理!
  9. 设计灵感|如何让你的海报更吸睛?
  10. 【Shell脚本】TDS离线备份还原
  11. 类库如何读取配置文件(app.config)?
  12. linux用户登录失败,锁定用户
  13. go语言阶段综合练习--家庭收支软件的示例--过程版本
  14. Marvelous Designer 服装设计与模拟
  15. HTML 网页自动刷新
  16. c语言中求圆台体积公式,圆台体积公式是什么
  17. 2022年手机CPU性能天梯图排行榜 手机处理器排行榜 2022
  18. oracle 大于当天时间_ORACLE日期时间函数大全
  19. element ui el-table单元格按需合并
  20. python数据分析:商品数据化运营(上)——知识点

热门文章

  1. 用CIL写程序:从“call vs callvirt”看方法调用
  2. Hadoop学习目录导航
  3. win10怎么用记事本打开html文件,Win10系统怎么打开记事本
  4. 多功能函数计算器(MATLAB实现)
  5. 调试过程中需要使用的工具
  6. kepware odata 接口访问地址
  7. 图书馆占座系统(SSM,JQUERY-EASYUI,MYSQL)
  8. 清华linux网络编程视频,清华大学视频课件:基于Linux的C++(自主模式)
  9. 初学必看,NFine框架结构加MVC快速开发平台登录流程梳理(附源码)
  10. 速达财务管理软件使用方法