基于UDP的网络聊天室(多线程实现收和发消息)
要求:1.有新用户登录,其他在线的用户可以收到登录信息
2.有用户群聊,其他在线的用户可以收到群聊信息
3.有用户退出,其他在线的用户可以收到退出信息
4.服务器可以发送系统信息
效果图:

service.c
#include <head.h>
typedef struct _MSG
{char type; // 类型 'L' 登录 'C' 群聊 'Q' 退出char name[32];char txt[128];
} msg_t;
typedef struct _NODE
{struct sockaddr_in clientaddr;struct _NODE *next;
} node_t;
void create_node(node_t **p);
void do_login(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);
void do_chat(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);
void do_quit(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);int main(int argc, const char *argv[])
{// 入参合理性检查if (argc != 3){printf("usage error:%s <ip> <port>...\n", argv[0]);exit(-1);}int sockfd = 0;// 创建套接字if (-1 == (sockfd = socket(AF_INET, SOCK_DGRAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);// 绑定if (-1 == (bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len))){perror("bind error");exit(-1);}node_t *phead = NULL;create_node(&phead);msg_t msg;// 收发数据char buff[128] = {0};pid_t pid = 0;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){// 子进程用于接收数据while (1){memset(&msg, 0, sizeof(msg));if (-1 == recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &clientaddr_len)){perror("recvfrom error");exit(-1);}printf("%s:%s\n", msg.name, msg.txt);switch (msg.type){case 'L':do_login(phead, msg, sockfd, clientaddr);break;case 'C':do_chat(phead, msg, sockfd, clientaddr);break;case 'Q':do_quit(phead, msg, sockfd, clientaddr);break;}}}else if (pid > 0){// 父进程用于发送数据// 把父进程当做一个客户端 以群聊的方式 把系统消息发给子进程strcpy(msg.name, "server");msg.type = 'C';while (1){memset(msg.txt, 0, 128);fgets(msg.txt, sizeof(msg.txt), stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("sento error");exit(-1);}}}close(sockfd);return 0;
}void create_node(node_t **p)
{*p = (node_t *)malloc(sizeof(node_t));memset(*p, 0, sizeof(node_t));
}
// 登录操作函数
void do_login(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 遍历链表 当前在线的所有人发“***加入了群聊”的消息node_t *ptemp = phead;while (ptemp->next != NULL){ptemp = ptemp->next;if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(ptemp->clientaddr), sizeof(ptemp->clientaddr))){perror("sento error");exit(-1);}}// 把新加入的群聊客户端网络信息结构体加入到链表中node_t *pnew = NULL;create_node(&pnew);pnew->clientaddr = clientaddr;pnew->next = phead->next;phead->next = pnew;return;
}
void do_chat(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 遍历链表 将群聊的消息 发给除了自己之外的所有人node_t *ptemp = phead;while (ptemp->next != NULL){ptemp = ptemp->next;if (memcmp(&clientaddr, &(ptemp->clientaddr), sizeof(clientaddr)) != 0){if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(ptemp->clientaddr), sizeof(ptemp->clientaddr))){perror("sento error");exit(-1);}}}return;
}
void do_quit(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 把 xxx 退出群聊的消息 发给在线的除自己的所有人 并且将自己在链表中删除node_t *ptemp = phead;while (ptemp->next != NULL){if (memcmp(&clientaddr, &(ptemp->next->clientaddr), sizeof(clientaddr)) != 0){if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(ptemp->next->clientaddr), sizeof(ptemp->next->clientaddr))){perror("sento error");exit(-1);}ptemp = ptemp->next;}else{node_t *pdel = ptemp->next;ptemp->next = pdel->next;free(pdel);pdel = NULL;}}return;
}
client.c
#include <head.h>
typedef struct _MSG
{char type; // 类型 'L' 登录 'C' 群聊 'Q' 退出char name[32];char txt[128];
} msg_t;int main(int argc, const char *argv[])
{// 入参合理性检查if (argc != 3){printf("usage error:%s <ip> <port>...\n", argv[0]);exit(-1);}int sockfd = 0;// 创建套接字if (-1 == (sockfd = socket(AF_INET, SOCK_DGRAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));msg_t msg;memset(&msg, 0, sizeof(msg));printf("请输入用户名:");fgets(msg.name, sizeof(msg.name), stdin);msg.name[strlen(msg.name) - 1] = '\0';msg.type = 'L';strcpy(msg.txt, "加入群聊");if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("sendto error");exit(-1);}// 收发数据char buff[128] = {0};pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){// 子进程用于接收数据while (1){memset(&msg, 0, sizeof(msg));if (-1 == recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL)){perror("recvfrom error");exit(-1);}printf("%s : %s\n", msg.name, msg.txt);}}else if(pid>0){// //父进程 在终端获取数据 发给服务器while (1){memset(msg.txt, 0, sizeof(msg.txt));fgets(msg.txt, 128,stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (strcmp(msg.txt, "quit") == 0){msg.type = 'Q';strcpy(msg.txt, "退出群聊");}else{msg.type = 'C';}if (-1 == sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("sendto error");exit(-1);}if ('Q' == msg.type){// 父进程退出之前先给子进程发信号 杀死子进程kill(pid, SIGKILL);wait(NULL);break;}}}close(sockfd);return 0;
}
相关文章:
基于UDP的网络聊天室(多线程实现收和发消息)
要求:1.有新用户登录,其他在线的用户可以收到登录信息 2.有用户群聊,其他在线的用户可以收到群聊信息 3.有用户退出,其他在线的用户可以收到退出信息 4.服务器可以发送系统信息 效果图: service.c #include <head…...
【脚本工具库】随机抽取数据 - 图像和标签对应(附源码)
在数据处理和机器学习任务中,我们经常需要从大规模数据集中随机抽取一定数量的图像及其对应的标签文件,以便进行模型训练、验证或测试。手动操作不仅耗时,而且容易出错。为了解决这个问题,我们可以编写一个Python脚本,…...
【python】eval函数
1.eval函数的语法及用法 (1)语法:eval(expression) 参数说明: expression:必须为字符串表达式,可为算法,也可为input函数等。 说明:表达式必需是字符串,否则会报错&a…...
实战|记一次java协同办公OA系统源码审计
前言 因为笔者也是代码审计初学者,写得不好的地方请见谅。该文章是以项目实战角度出发,希望能给大家带来启发。 审计过程 审计思路 1、拿到一个项目首先要看它使用了什么技术框架,是使用了ssh框架,还是使用了ssm框架ÿ…...
浅浅谈谈如何利用Javase+多线程+计算机网络的知识做一个爬CSDN阅读量总访问量的程序
目录 我们发现csdn的文章 首先为了印证我们的想法 我们用postman往csdn我们任意一篇文章发起post请求 发送请求 编辑获得响应结果 我们发现我们的阅读量上涨 PostRequestSender类 但是我们经过测试发现 定义一个字符串数组 把URL放进去 然后延迟启动 在线程池里面…...
Vscode 中launch.json与tasks.json文件
Vscode 中launch.json与tasks.json文件 launch.json文件基本结构主要属性示例配置PythonCNode.js 常见配置项1. Python2. C3. Node.js 使用示例 tasks.json基本结构主要属性示例配置C 编译任务Python 运行任务Node.js 运行任务 常见配置项使用示例 tasks.json与launch.json文件…...
C#基于SkiaSharp实现印章管理(2)
上一篇文章最后提到基于System.Text.Json能够序列化SKColor对象,但是反序列化时却无法解析本地json数据。换成Newtonsoft.Json进行序列化和反序列化也是类似的问题。 通过百度及查看微软的帮助文档,上述情况下需自定义转换类以处理SKColor类型数据的…...
大二C++期末复习(自用)
一、类 1.定义成员函数 输入年份判断是否是闰年,若是输出年份;若不是,输出NO #include<iostream> #include<cstring> using namespace std; class TDate{private:int month;int day;int year;public:TDate(int y,int m,int d)…...
重大进展!微信支付收款码全场景接入银联网络
据中国银联6月19日消息,近日,银联网络迎来微信支付收款码场景的全面接入,推动条码支付互联互通取得新进展,为境内外广大消费者提供更多支付选择、更好支付体验。 2024年6月,伴随微信支付经营收款码的开放,微…...
msvcr110.dll丢失的解决方法,亲测有效的几种解决方法
最近,我在启动一个程序时,系统突然弹出一个错误提示,告诉我电脑缺失了一个名为msvcr110.dll的文件。这让我感到非常困惑,因为我之前从未遇到过这样的问题。经过一番搜索和尝试,我总结了5种靠谱的解决方法。下面分享给大…...
SUSE Linux 15 sp5上Nginx安装配置升级
1.安装SUSE linux 15 SP5 图形化界面安装很简单,选择最小安装,安装好后,使用vim编辑配置文件,结果提示"bash: vim: command not found"。 最简安装把一些常用命令都整没有了,于是又重新选择了Server Applica…...
突破Web3红海,DePIN如何构建创新生态系统?
撰文:TinTinLand 本文来源香港Web3媒体Techub News专栏作者TinTinLand 2023 年 DePIN 赛道的火热成为 Web3 行业的重点关注方向,当前如何以可扩展、去中心化、安全方式推动 DePIN 赛道赋能下的 AI 版图建设,寻找更多 Web3 行业创新机遇成为…...
裸机与操做系统区别(RTOS)
声明:该系列笔记是参考韦东山老师的视频,链接放在最后!!! rtos:这种系统只实现了内核功能,比较简单,在嵌入式开发中,某些情况下我们只需要多任务,而不需要文件…...
详解 ClickHouse 的分片集群
一、简介 分片功能依赖于 Distributed 表引擎,Distributed 表引擎本身不存储数据,有点类似于 MyCat 之于 MySql,成为一种中间件,通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据 ClickHouse 进行分片集群的…...
AI问答-医疗:什么是“手术报台”
手术报台并不是传统意义上的医疗工具或设备,而是一个与手术耗材追溯管理相关的系统或工具。以下是对手术报台的详细解释: 一、定义与功能 手术报台系统,如医迈德手术报台系统,是一款面向医院跟台人员的微信小程序。 它通过手术耗…...
S-Clustr(影子集群)V3 高并发,去中心化,多节点控制
S-Clustr 项目地址:https://github.com/MartinxMax/S-Clustr/releases/tag/S-Clustr-V3.0 Maptnh Не ограничивайте свои действия виртуальным миром. GitHub: Maptnh Jay Steinberg Man kann die Menschen, die man hasst, in d…...
支持WebDav的网盘infiniCloud(静读天下,Zotero 等挂载)
前言 WebDav是一种基于HTTP的协议,允许用户在Web上直接编辑和管理文件,如复制、移动、删除等。 尽管有一些网盘支持WebDav,但其中大部分都有较多的使用限制。这些限制可能包括:上传文件的大小限制、存储空间的限制、下载速度的限…...
Linux命令行导出MySQL数据库备份并压缩
Linux命令行导出MySQL数据库备份并压缩 导出SQL: 如果使用的是 MySQL 或者 MariaDB 可以使用mysqldump工具进行数据备份的导出; 基本命令: mysqldump -u用户名 -p密码 数据库名称 > 要导出的文件名.sql替换掉你实际的数据库“用户名”…...
二叉树的广度优先搜索(层次遍历)
目录 定义 层序遍历的数据结构 实现过程简述 具体代码 定义 层序遍历就是从左到右一层一层地遍历二叉树。 层序遍历的数据结构 层序遍历需要借用一个辅助数据结构实现,由于队列具有先进先出的特性,符合一层一层遍历的逻辑,而栈先进后出…...
AU音频重新混合音频,在 Adobe Audition 中无缝延长背景音乐,无缝缩短BGM
导入音频,选中音频,并且点 New Multitrack Session 的图标 设计文件名和存储路径,然后点 OK 点 Essential Sound 面板点 Music (如果没有这个面板 点菜单栏 Windows > Essential Sound 调出来) 点 Duration 展…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
【系统架构设计师-2025上半年真题】综合知识-参考答案及部分详解(回忆版)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20~21题】【第…...
