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

基于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的网络聊天室(多线程实现收和发消息)

要求&#xff1a;1.有新用户登录&#xff0c;其他在线的用户可以收到登录信息 2.有用户群聊&#xff0c;其他在线的用户可以收到群聊信息 3.有用户退出&#xff0c;其他在线的用户可以收到退出信息 4.服务器可以发送系统信息 效果图&#xff1a; service.c #include <head…...

【脚本工具库】随机抽取数据 - 图像和标签对应(附源码)

在数据处理和机器学习任务中&#xff0c;我们经常需要从大规模数据集中随机抽取一定数量的图像及其对应的标签文件&#xff0c;以便进行模型训练、验证或测试。手动操作不仅耗时&#xff0c;而且容易出错。为了解决这个问题&#xff0c;我们可以编写一个Python脚本&#xff0c;…...

【python】eval函数

1.eval函数的语法及用法 &#xff08;1&#xff09;语法&#xff1a;eval(expression) 参数说明&#xff1a; expression&#xff1a;必须为字符串表达式&#xff0c;可为算法&#xff0c;也可为input函数等。 说明&#xff1a;表达式必需是字符串&#xff0c;否则会报错&a…...

实战|记一次java协同办公OA系统源码审计

前言 因为笔者也是代码审计初学者&#xff0c;写得不好的地方请见谅。该文章是以项目实战角度出发&#xff0c;希望能给大家带来启发。 审计过程 审计思路 1、拿到一个项目首先要看它使用了什么技术框架&#xff0c;是使用了ssh框架&#xff0c;还是使用了ssm框架&#xff…...

浅浅谈谈如何利用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对象&#xff0c;但是反序列化时却无法解析本地json数据。换成Newtonsoft.Json进行序列化和反序列化也是类似的问题。   通过百度及查看微软的帮助文档&#xff0c;上述情况下需自定义转换类以处理SKColor类型数据的…...

大二C++期末复习(自用)

一、类 1.定义成员函数 输入年份判断是否是闰年&#xff0c;若是输出年份&#xff1b;若不是&#xff0c;输出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日消息&#xff0c;近日&#xff0c;银联网络迎来微信支付收款码场景的全面接入&#xff0c;推动条码支付互联互通取得新进展&#xff0c;为境内外广大消费者提供更多支付选择、更好支付体验。 2024年6月&#xff0c;伴随微信支付经营收款码的开放&#xff0c;微…...

msvcr110.dll丢失的解决方法,亲测有效的几种解决方法

最近&#xff0c;我在启动一个程序时&#xff0c;系统突然弹出一个错误提示&#xff0c;告诉我电脑缺失了一个名为msvcr110.dll的文件。这让我感到非常困惑&#xff0c;因为我之前从未遇到过这样的问题。经过一番搜索和尝试&#xff0c;我总结了5种靠谱的解决方法。下面分享给大…...

SUSE Linux 15 sp5上Nginx安装配置升级

1.安装SUSE linux 15 SP5 图形化界面安装很简单&#xff0c;选择最小安装&#xff0c;安装好后&#xff0c;使用vim编辑配置文件&#xff0c;结果提示"bash: vim: command not found"。 最简安装把一些常用命令都整没有了&#xff0c;于是又重新选择了Server Applica…...

突破Web3红海,DePIN如何构建创新生态系统?

撰文&#xff1a;TinTinLand 本文来源香港Web3媒体Techub News专栏作者TinTinLand 2023 年 DePIN 赛道的火热成为 Web3 行业的重点关注方向&#xff0c;当前如何以可扩展、去中心化、安全方式推动 DePIN 赛道赋能下的 AI 版图建设&#xff0c;寻找更多 Web3 行业创新机遇成为…...

裸机与操做系统区别(RTOS)

声明&#xff1a;该系列笔记是参考韦东山老师的视频&#xff0c;链接放在最后&#xff01;&#xff01;&#xff01; rtos&#xff1a;这种系统只实现了内核功能&#xff0c;比较简单&#xff0c;在嵌入式开发中&#xff0c;某些情况下我们只需要多任务&#xff0c;而不需要文件…...

详解 ClickHouse 的分片集群

一、简介 分片功能依赖于 Distributed 表引擎&#xff0c;Distributed 表引擎本身不存储数据&#xff0c;有点类似于 MyCat 之于 MySql&#xff0c;成为一种中间件&#xff0c;通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据 ClickHouse 进行分片集群的…...

AI问答-医疗:什么是“手术报台”

手术报台并不是传统意义上的医疗工具或设备&#xff0c;而是一个与手术耗材追溯管理相关的系统或工具。以下是对手术报台的详细解释&#xff1a; 一、定义与功能 手术报台系统&#xff0c;如医迈德手术报台系统&#xff0c;是一款面向医院跟台人员的微信小程序。 它通过手术耗…...

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的协议&#xff0c;允许用户在Web上直接编辑和管理文件&#xff0c;如复制、移动、删除等。 尽管有一些网盘支持WebDav&#xff0c;但其中大部分都有较多的使用限制。这些限制可能包括&#xff1a;上传文件的大小限制、存储空间的限制、下载速度的限…...

Linux命令行导出MySQL数据库备份并压缩

Linux命令行导出MySQL数据库备份并压缩 导出SQL&#xff1a; 如果使用的是 MySQL 或者 MariaDB 可以使用mysqldump工具进行数据备份的导出&#xff1b; 基本命令&#xff1a; mysqldump -u用户名 -p密码 数据库名称 > 要导出的文件名.sql替换掉你实际的数据库“用户名”…...

二叉树的广度优先搜索(层次遍历)

目录 定义 层序遍历的数据结构 实现过程简述 具体代码 定义 层序遍历就是从左到右一层一层地遍历二叉树。 层序遍历的数据结构 层序遍历需要借用一个辅助数据结构实现&#xff0c;由于队列具有先进先出的特性&#xff0c;符合一层一层遍历的逻辑&#xff0c;而栈先进后出…...

AU音频重新混合音频,在 Adobe Audition 中无缝延长背景音乐,无缝缩短BGM

导入音频&#xff0c;选中音频&#xff0c;并且点 New Multitrack Session 的图标 设计文件名和存储路径&#xff0c;然后点 OK 点 Essential Sound 面板点 Music &#xff08;如果没有这个面板 点菜单栏 Windows > Essential Sound 调出来&#xff09; 点 Duration 展…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...