当前位置: 首页 > news >正文

UDP -- 简易聊天室

目录

gitee(内有详细代码)

图解

MessageRoute.hpp

UdpClient.hpp

UdpServer.hpp

Main.hpp

运行结果(本地通信)

如何分开对话显示?


gitee(内有详细代码)

chat_room · zihuixie/Linux_Learning - 码云 - 开源中国icon-default.png?t=O83Ahttps://gitee.com/zihuixie/linux_-learning/tree/master/chat_room

图解

MessageRoute.hpp

#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"// 通信模块:实现消息的转发
//只要有人发消息,就把该消息转发给所有的在线用户using task_t =std::function<void()>;class MessageRoute
{
private:// 判断地址是否已保存数组中bool IsExists(const InetAddr &addr){for (auto a : _online_user){if (a == addr)return true;}return false;}public:MessageRoute(){pthread_mutex_init(&_mutex,nullptr);}~MessageRoute(){pthread_mutex_destroy(&_mutex);}// 添加用户void Adduser(const InetAddr &addr){LockGuard lock(&_mutex);//保护数组临界资源// 已存在则不添加if (IsExists(addr))return;_online_user.push_back(addr);}// 删除用户void Deluser(const InetAddr &addr){LockGuard lock(&_mutex);//保护数组临界资源// 不存在该用户,不需要删除if (!IsExists(addr))return;// 用迭代器删除for (auto iter = _online_user.begin(); iter != _online_user.end(); iter++){if (*iter == addr){_online_user.erase(iter);break;}}}//转发消息void RouteHelper(int sockfd,std::string message,InetAddr who){LockGuard lock(&_mutex);for(auto user:_online_user){//设置要发送的消息std::string send_message ="\n["+who.Ip()+":"+std::to_string(who.Port())+"]# "+message+"\n";struct sockaddr_in clientaddr=user.Addr();::sendto(sockfd,send_message.c_str(),send_message.size(),0,(struct sockaddr*)&clientaddr,sizeof(clientaddr));}}//通信模块//哪个套接字,发了什么消息,谁发的void Route(int sockfd,std::string message,InetAddr who){Adduser(who);//该用户要退出,删除该用户if(message=="Q" || message=="QUIT")Deluser(who);task_t t=std::bind(&MessageRoute::RouteHelper,this,sockfd,message,who);//让线程池来转发ThreadPool<task_t>::GetInstance()->Enqueue(t);}
private:pthread_mutex_t _mutex;std::vector<InetAddr> _online_user; // 用数组存储在线用户(用地址代表用户)
};

UdpClient.hpp

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Thread.hpp"using namespace ThreadModule;void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " serverip serverport\n"<< std::endl;
}int InitClient(std::string &serverip, uint16_t serverport, struct sockaddr_in *server)
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;return -1;}// 初始化地址memset(server, 0, sizeof(struct sockaddr_in));server->sin_family = AF_INET;server->sin_port = htons(serverport);server->sin_addr.s_addr = inet_addr(serverip.c_str());return sockfd;
}// 接收消息
void recvmessage(int sockfd, std::string name)
{while (true){// 发送方的地址struct sockaddr_in peer;socklen_t len = sizeof(peer);char buffer[1024];// 获取接收方的地址ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){buffer[n] = 0;//向标准错误中输出(标准错误也是个文件描述符)fprintf(stderr, "[%s]%s\n", name.c_str(), buffer);}}
}void sendmessage(int sockfd, struct sockaddr_in &server, std::string name)
{std::string message;while (true){printf("%s | Enter# ", name.c_str());fflush(stdout);std::getline(std::cin, message);// 传接收方的地址sendto(sockfd, message.c_str(), sizeof(message), 0, (struct sockaddr *)&server, sizeof(server));}
}int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}//填充地址struct sockaddr_in serveraddr;std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);int sockfd = InitClient(serverip, serverport, &serveraddr);if (sockfd == -1){return 1;}//定义函数并绑定参数func_t r = std::bind(&recvmessage, sockfd, std::placeholders::_1);func_t s = std::bind(&sendmessage, sockfd, serveraddr, std::placeholders::_1);//创建两个线程:发消息 && 收消息//就可以同时实现收消息 && 发消息 -- 全双工//如果收消息 和 发消息 都由一个线程实现 -- 半双工Thread Recver(r, "recver");Thread Sender(s, "sender");//启动线程Recver.Start();Sender.Start();Recver.Join();Sender.Join();return 0;
}

UdpServer.hpp

#pragma once#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <functional>
#include "InetAddr.hpp"
#include "Log.hpp"enum
{SOCKET_ERROR = 1, // 套接字创建失败BIND_ERROR,       // 绑定失败USAGE_ERROR       // 用法错误
};const static int defaultfd = -1; // 默认描述符的值为-1// 接收任务
using hander_message_t = std::function<void(int sockfd, const std::string message, const InetAddr who)>;class UdpServer
{
public:// 外界需要传端口号UdpServer(uint16_t port, hander_message_t hander_message): _port(port), _sockfd(defaultfd), _isrunning(false), _hander_message(hander_message){}void InitServer(){// 创建套接字_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0) // 创建失败{LOG(FATAL, "socket error, %s, %d\n", strerror(errno), errno);exit(SOCKET_ERROR);}LOG(INFO, "socket create success, sockfd: %d\n", _sockfd);// 填 sockaddr_instruct sockaddr_in local;     // 在栈上开辟空间bzero(&local, sizeof(local)); // 将内存设置为全0local.sin_family = AF_INET;         // 协议族(用哪个协议)local.sin_port = htons(_port);      // 端口号,转为网络序列(大端)local.sin_addr.s_addr = INADDR_ANY; // IP地址(任意地址)int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));// 绑定失败if (n < 0){LOG(FATAL, "bind error,%s,%d\n", strerror(errno), errno);exit(BIND_ERROR);}LOG(INFO, "socket bind success\n");}// 启动服务器,服务器只接收信息和做应答void Start(){_isrunning = true;while (true){char message[1024];struct sockaddr_in peer; // 发送方的地址socklen_t len = sizeof(peer);// 接收数据报,返回值为接收到的字节数ssize_t n = recvfrom(_sockfd, message, sizeof(message) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){message[n] = 0;InetAddr addr(peer); // 发送方的IP和端口号LOG(DEBUG, "get message from [%s:%d]:%s\n", addr.Ip().c_str(), addr.Port(), message);//转发消息_hander_message(_sockfd,message,addr);}_isrunning = false;}}~UdpServer(){}private:int _sockfd;uint16_t _port;bool _isrunning;hander_message_t _hander_message;
};

Main.hpp

#include<iostream>
#include<memory>
#include"UdpServer.hpp"
#include"MessageRoute.hpp"void Usage(std::string proc)
{std::cout<<"Usage:\n\t"<<proc<<" local_port\n"<<std::endl;
}int main(int argc,char* argv[])
{if(argc!=2){Usage(argv[0]);exit(USAGE_ERROR);}EnableScreen();MessageRoute route;//创建一个实例uint16_t port=std::stoi(argv[1]);std::unique_ptr<UdpServer> usvr=std::make_unique<UdpServer>(port,std::bind(&MessageRoute::Route,&route,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));usvr->InitServer();usvr->Start();return 0;}

运行结果(本地通信)

如何分开对话显示?

在启动客户端时,打开两个对话,输入命令 ./udpclient 127.0.0.1 8080 2>/dev/pts/2

相关文章:

UDP -- 简易聊天室

目录 gitee&#xff08;内有详细代码&#xff09; 图解 MessageRoute.hpp UdpClient.hpp UdpServer.hpp Main.hpp 运行结果&#xff08;本地通信&#xff09; 如何分开对话显示&#xff1f; gitee&#xff08;内有详细代码&#xff09; chat_room zihuixie/Linux_Lear…...

NVIDIA在CES 2025上的三大亮点:AI芯片、机器人与自动驾驶、全新游戏显卡

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

【通俗理解】AI的两次寒冬:从感知机困局到深度学习前夜

AI的两次寒冬&#xff1a;从感知机困局到深度学习前夜 引用&#xff08;中英双语&#xff09; 中文&#xff1a; “第一次AI寒冬&#xff0c;是因为感知机局限性被揭示&#xff0c;让人们失去了对算法可行性的信心。” “第二次AI寒冬&#xff0c;则是因为专家系统的局限性和硬…...

transformer深度学习实战CCTSDB中国交通标志识别

本文采用RT-DETR作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。RT-DETR以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对CCTSDB交通标志数据集进行训练和优化&#xff0c;该数据集包含丰富的CCTSDB交…...

JavaWeb开发(六)XML介绍

1. XML介绍 1.1. 什么是XML &#xff08;1&#xff09;XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种很像HTML的标记语言。   &#xff08;2&#xff09;XML 的设计宗旨是传输数据(目前主要是作为配置文件)&#xff0c;而不是显示数据。   &#xff08;3&a…...

使用pbootcms开发一个企业官网

V:llike620 pbootcms开源PHP建站系统 https://www.pbootcms.com/ 配置网站 域名解析后&#xff0c;网站绑定到程序根目录即可 例如&#xff1a;本地域名是dobot.test &#xff0c;那么也要同步本地的hosts是 127.0.0.1 dobot.test 需要配置下伪静态规则 location / {if (!-e $r…...

Linux C编程——文件IO基础

文件IO基础 一、简单的文件 IO 示例二、文件描述符三、open 打开文件1. 函数原型2. 文件权限3. 宏定义文件权限4. 函数使用实例 四、write 写文件五、read 读文件六、close 关闭文件七、Iseek 绍 Linux 应用编程中最基础的知识&#xff0c;即文件 I/O&#xff08;Input、Outout…...

【信息系统项目管理师】高分论文:论信息系统项目的风险管理(人民医院的信息系统)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划风险管理2、项目风险识别3、风险定性分析4、风险定量分析5、制定风险应对6、实施风险应对计划7、监督风险论文 2022年6月,我作为项目经理承担了XX县人民医院的信息系统建设,该项目总投资300万,其…...

UE播放声音

蓝图中有两个播放声音的函数 Play Sound 2D 和 Play Sound at Location Play Sound 2D没有声音距离衰减&#xff0c;一般用于界面ui Play Sound at Location 有声音距离衰减&#xff0c;一般用于枪声&#xff0c;场景声等&#xff0c;比较常用...

Docker Compose 启动 Harbor 并指定网络

1. 介绍 Harbor 是一个开源的企业级 Docker 镜像仓库&#xff0c;提供镜像存储、访问控制、安全扫描等功能。使用 Docker Compose 启动 Harbor 时&#xff0c;您可以指定一个自定义网络&#xff0c;以便管理容器之间的网络通信。在本示例中&#xff0c;我们将创建一个名为 har…...

WebSocket 实战案例:从设计到部署

在前六篇文章中,我们深入探讨了 WebSocket 的基础原理、服务端开发、客户端实现、安全实践、性能优化和测试调试。今天,让我们通过一个实战案例,看看如何将这些知识应用到实际项目中。我曾在一个大型在线教育平台中,通过 WebSocket 实现了实时互动课堂,支持了数万名师生的同时在…...

selenium合集

环境搭建步骤 安装selenium pip install selenium 安装浏览器 安装浏览器驱动 谷歌浏览器&#xff1a;chromdriver.exe ie浏览器:ieserverdriver.exe FireFox浏览器:geckodriver.exe 特别注意⚠️&#xff1a;下载驱动版本必须与浏览器版本一致 下载地址 淘宝镜像&#xff1…...

JVM生产环境常用参数配置及调优建议

一、生产常用参数配置 JAVA_OPTS"-server -Xms3000m -Xmx3000m -Xmn1500m -XX:UseG1GC -XX:ConcGCThreads8 -XX:PrintGCDetails -XX:PrintGCTimeStamps -Xloggc:./g1-gc.log -XX:MaxMetaspaceSize256m -XX:-UseGCOverheadLimit -XX:UseCompressedOops -XX:HeapDumpOnOu…...

Spring Boot 3 实现 MySQL 主从数据库之间的数据同步

✅ Spring Boot 3 实现 MySQL 主从数据库之间的数据同步 在实际项目中&#xff0c;为了提高 系统的读性能 和 数据的可用性&#xff0c;通常会使用 主从数据库架构。Spring Boot 提供了对 多数据源 的良好支持&#xff0c;可以轻松配置 主从数据库 的数据同步&#xff0c;实现…...

【小程序开发】- 小程序版本迭代指南(版本发布教程)

一&#xff0c;版本号 版本号是小程序版本的标识&#xff0c;通常由一系列数字组成&#xff0c;如 1.0.0、1.1.0 等。版本号的格式通常是 主版本号.次版本号.修订号 主版本号&#xff1a;当小程序有重大更新或不兼容的更改时&#xff0c;主版本号会增加。 次版本号&#xff1a…...

MySQL 间隙锁避免“可重复读”出现“幻读”

在数据库事务处理中&#xff0c;可重复读&#xff08;Repeatable Read&#xff09;是一个常用的隔离级别&#xff0c;但其默认行为可能导致幻读现象。然而&#xff0c;在 MySQL 的实现中&#xff0c;通过 **间隙锁&#xff08;Gap Lock&#xff09;**机制&#xff0c;能够避免幻…...

揭秘区块链隐私黑科技:零知识证明如何改变未来

文章目录 1. 引言&#xff1a;什么是零知识证明&#xff1f;2. 零知识证明的核心概念与三大属性2.1 完备性&#xff08;Completeness&#xff09;2.2 可靠性&#xff08;Soundness&#xff09;2.3 零知识性&#xff08;Zero-Knowledge&#xff09; 3. 零知识证明的工作原理4. 零…...

JavaWeb开发:从入门到精通

近年来&#xff0c;JavaWeb开发已经成为了互联网开发领域的重要技术之一。无论是大型企业还是个人项目&#xff0c;都离不开JavaWeb开发。本文将为您介绍JavaWeb开发的基本概念、常用技术和开发流程&#xff0c;帮助您快速入门并掌握这一技术。 一、JavaWeb开发的基本概念 Jav…...

2025年01月07日Github流行趋势

项目名称&#xff1a;khoj 项目地址url&#xff1a;https://github.com/khoj-ai/khoj项目语言&#xff1a;Python历史star数&#xff1a;20105今日star数&#xff1a;363项目维护者&#xff1a;debanjum, sabaimran, MythicalCow, aam-at, shantanuSakpal项目简介&#xff1a;你…...

c#集成npoi根据excel模板导出excel

NuGet中安装npoi 创建excel模板&#xff0c;替换其中的内容生成新的excel文件。 例子中主要写了这四种情况&#xff1a; 1、替换单个单元格内容&#xff1b; 2、替换横向多个单元格&#xff1b; 3、替换表格&#xff1b; 4、单元格中插入图片&#xff1b; using System.IO; …...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...