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

基于UDP的网络多人聊天室

UDP服务器

#include <myheader.h>//宏定义打印错误信息
#define PRINT_ERR(msg)                                  \do                                                  \{                                                   \printf("%S,%D,%S\n",__FILE__,__LINE__,__func__);\perror(msg);                                    \exit(-1);                                       \}while(0);//定义一个结构体
//由于客户端给服务器发送第数据内容较多,定义一个结构体来发送
typedef struct
{char code;  //操作码 ‘L’登录 ‘C’群聊 ‘Q’退出char name[32];   //保存登录用户名char txt[128];   //保存发送的信息
}msg_t;//定义一个链表
// 给在线所有客户端发送数据,将每一个客户端的信息用链表来保存
typedef struct NODE
{struct sockaddr_in c_addr;   //数据域  客户端第网络信息结构体struct NODE *next;   // 指针域   保存下一个结点的地址
}node_t;//创建一个链表头第函数,定义链表头结点
//链表头结点函数
void creat_link(node_t **head)
{*head = (node_t *)malloc(sizeof(node_t));
}int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍历链表将登录信息发送给所以人node_t *p = phead;while (p->next != NULL){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}//将登录的客户端信息插入保存在链表//头插//定义一个新的指针保存客户端信息node_t *newp = NULL;creat_link(&newp);newp->c_addr = clientaddr;newp->next = phead->next;phead->next = newp;return 0;
}int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍历链表,将消息发给除自己之外的所有人node_t *p = phead;while (p->next != NULL){p = p->next;//判断链表客户端信息是否是自己//是自己就不发送if (memcmp(&(p->c_addr), &clientaddr, sizeof(clientaddr))){if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}}return 0;
}//退出群聊操作
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{node_t *p = phead;while (p->next != NULL){//判断链表客户端信息是否是自己//是自己就不发送并且将自己的客户端信息在链表内删除if (memcmp(&(p->next->c_addr), &clientaddr, sizeof(clientaddr))){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){perror("recvfrom error");}}else{node_t *pnew;pnew = p->next;p->next = pnew->next;pnew->next = NULL;free(pnew);pnew = NULL;}}return 0;
}int main(int argc, const char *argv[])
{//入参合理性判断if(argc != 3){printf("age:%s ip port\n",argv[0]);return -1;}//创建套接字int sfd = socket(AF_INET,SOCK_DGRAM,0);if(sfd == -1){perror("socket error");return -1;}printf("sfd = %d\n",sfd);//创建服务器网络信息结构体struct sockaddr_in sin;memset(&sin,0,sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(atoi(argv[2]));sin.sin_addr.s_addr = inet_addr(argv[1]);socklen_t sin_len = sizeof(sin);//绑定if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1){perror("bind error");return -1;}printf("bind success\n");//创建客户端的网络信息结构体struct sockaddr_in cin;memset(&cin,0,sizeof(cin));socklen_t cin_len = sizeof(cin);msg_t msg;//建一个父子进程 //用来实现服务器既可以发送系统消息,又可以接收客户端的信息pid_t pid;pid = fork();if(pid == -1){//创建错误perror("fork error");}else if(pid == 0){//子进程//接收数据并处理//循环接收客户端发来的信息,通过Switch判断code所存的协议//定义链表头结点node_t *phead = NULL;creat_link(&phead);phead->next = NULL;//循环接受客户端发来的信息并通过switch进行判断执行哪个功能函数while (1){memset(&msg, 0, sizeof(msg));//清空操作memset(&cin, 0, sizeof(cin));//清空操作if ((recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &cin_len)) == -1){perror("recvfrom error");}printf("%8s : [%s]\n", msg.name, msg.txt);switch (msg.code){case 'L':do_register(sfd, msg, cin, phead);break;case 'C':do_group_chat(sfd, msg, cin, phead);break;case 'Q':quit_group_chat(sfd, msg, cin, phead);break;}}}else if(pid > 0){//父进程//发送系统信息//视为一个客户端,向子进程发送消息给在线客户msg.code='C';strcpy(msg.name,"server");while(1){fgets(msg.txt,128,stdin);msg.txt[strlen(msg.txt)-1]='\0';if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&sin,sin_len)==-1){perror("sendto error");}}close(sfd);return 0;}return 0;
}

UDP客户端

#include <myheader.h>//宏定义打印错误信息
#define perror(msg)                                      \do                                                      \{                                                       \printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); \perror(msg);                                        \exit(-1);                                           \} while (0)typedef struct
{char code; //操作码 'L' 登录  'C' 群聊  'Q' 退出char name[32];char txt[128];
} msg_t;int main(int argc, const char *argv[])
{//入参合理性判断if (argc != 3){printf("age:%s ip port\n", argv[0]);return -1;}//创建套接字int sfd;if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){perror("socket error");}//创建服务器网络信息结构体struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.s_addr = inet_addr(argv[1]);sin.sin_port = htons(atoi(argv[2]));socklen_t sin_len = sizeof(sin);//给服务器发送登录数据包msg_t msg;memset(&msg, 0, sizeof(msg_t));msg.code = 'L';printf("请输入用户名:");fgets(msg.name, 32, stdin);msg.name[strlen(msg.name) - 1] = '\0';strcpy(msg.txt, "加入群聊");if (sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&sin, sin_len) == -1){perror("sendto error");}//创建父子进程pid_t pid;pid = fork();if (pid == -1){perror("fork error");}else if (pid == 0){//子进程//接受数据并处理while (1){//每次循环前将msg置零memset(&msg, 0, sizeof(msg));//接受服务器发过来的信息并打印到终端上if (recvfrom(sfd, &msg, sizeof(msg_t), 0, NULL, NULL) == -1){perror("recvfrom error");}printf("%8s:[%s]\n", msg.name, msg.txt);}}else if (pid > 0){//父进程//发送消息while (1){   //memset会把name清除msg.code = 'C';fgets(msg.txt, 128, stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (strcmp(msg.txt, "quit") == 0){msg.code = 'Q';strcpy(msg.txt, "退出群聊");}if (sendto(sfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&sin, sin_len) == -1){perror("sendto error");}if (strcmp(msg.txt, "退出群聊") == 0){break;}}kill(pid,SIGKILL);wait(NULL);close(sfd);}return 0;
}

相关文章:

基于UDP的网络多人聊天室

UDP服务器 #include <myheader.h>//宏定义打印错误信息 #define PRINT_ERR(msg) \do \{ \printf("%S,%D,%S\n",__FI…...

美国FDA认证是什么,食品FDA注册申请流程

​美国FDA认证是什么&#xff1f; 美国FDA认证&#xff0c;全称为美国食品药品监督管理局&#xff08;Food and Drug Administration&#xff09;的认证&#xff0c;是美国政府为了确保食品、药品、医疗器械等产品的安全性和有效性所设立的重要制度。FDA认证的种类繁多&#x…...

golang的context和chan 的使用

1. context 作用 context包的context的接口&#xff0c;主要是控制协程执行上下文的时间&#xff0c;以及取消程序的执行&#xff0c;以及上下文中传递数据等作用&#xff0c;golang中耗时或者需要协同的操作都会见到context的身影。 context有几个常用的方法 1.1 context.B…...

洛谷P3574 [POI2014] FAR-FarmCraft(树形dp)

洛谷 P 3574 [ P O I 2014 ] F A R − F a r m C r a f t &#xff08;树形 d p &#xff09; \Huge{洛谷P3574 [POI2014] FAR-FarmCraft&#xff08;树形dp&#xff09;} 洛谷P3574[POI2014]FAR−FarmCraft&#xff08;树形dp&#xff09; 文章目录 题意题目说明 思路标程 题目…...

vue/core源码中ref源码的js化

起源&#xff1a; 当看见reactivity文件中的ref.ts文件长达五百多的ts代码后&#xff0c;突发奇想想看下转化成js有多少行。 进行转化&#xff1a; let shouldTrack true; // Define shouldTrack variable let activeEffect null; // Define activeEffect variable// 定义…...

准备打ccf

准备打ccf...

k8s遇到的错误记录

时隔四年有开始重新鼓捣k8s了&#xff0c;重新安装后遇到的错误记录如下&#xff1a; Error: Package: kubelet-1.14.0-0.x86_64 (kubernetes) Requires: kubernetes-cni 0.7.5 Available: kubernetes-cni-0.3.0.1-0.07a8a2.x86_64 (kubernetes) …...

全局平均池化笔记

全局平均池化&#xff08;Global Average Pooling, GAP&#xff09;是一种用于卷积神经网络&#xff08;CNN&#xff09;中的池化操作&#xff0c;其主要作用和优点包括&#xff1a; 减少参数数量&#xff1a;全局平均池化层将每个特征图通过取其所有元素的平均值&#xff0c;压…...

【数仓系列】maxcompute、postgresql、sparksql等行转列数据处理实战总结(其他类型持续总结更新)

1.熟悉、梳理、总结项目研发实战中的SQL开发日常使用中的问题、经验总结&#xff0c;都是常用的开发技能&#xff0c;可以省去很多时间&#xff0c;时间长就忘记了 2.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 文章目录 1.maxcompu…...

用数据,简单点!奇点云2024 StartDT Day数智科技大会,直播见

在充满挑战的2024&#xff0c;企业如何以最小化的资源投入和试错成本&#xff0c;挖掘新的增长机会&#xff0c;实现确定性发展&#xff1f; “简单点”是当前商业环境的应对策略&#xff0c;也是奇点云2024 StartDT Day的核心理念。 5月28日&#xff0c;由奇点云主办的2024 S…...

Cloneable接口和深拷贝

在java中如何对对象进行拷贝呢&#xff1f;我们可以使用Object类中的clone方法。 一、浅拷贝 在使用clone方法对对象进行拷贝的时候&#xff0c;需要注意&#xff1a; 1.需要重写clone方法&#xff1b; 2.clone方法的返回值是Object类&#xff0c;需要强制类型转化&#xf…...

C++:vector的介绍及使用

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 文章目录 前言 一、vector的介绍 二、vector的使用 2.1.构造和赋值重载&#xff08;Member functions&#xff09; 2.2 vector iterator 的使用 2.3 vector 空间增长问题 2.4 vector 增删查改 三 sort 四 v…...

【机器学习】大模型在机器学习中的应用:从深度学习到生成式人工智能的演进

&#x1f512;文章目录&#xff1a; &#x1f4a5;1.引言 ☔2.大模型概述 &#x1f6b2;3.大模型在深度学习中的应用 &#x1f6f4;4.大模型在生成式人工智能中的应用 &#x1f44a;5.大模型的挑战与未来展望 &#x1f4a5;1.引言 随着数据量的爆炸性增长和计算能力的提…...

营销短信XML接口对接发送示例

在现代社会中&#xff0c;通信技术日新月异&#xff0c;其中&#xff0c;短信作为一种快速、简便的通信方式&#xff0c;仍然在日常生活中占据着重要的地位。为了满足各种应用场景的需求&#xff0c;短信接口应运而生&#xff0c;成为了实现高能有效通信的关键。 短信接口是一种…...

【C语言刷题系列】求一个数组中两个元素a和b的和最接近整数m

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;C语言刷题系列 目录 一、问题描述 二、解题思路 解题思路&#xff1a; 解题步骤: 三、C语言代码实现及测试 一、问题描述 给定一…...

Python pdf2imges -- pdf文件转图片

pdf文件转图片&#xff0c;需要安装PyMuPDF包&#xff0c;具体PyMuPDF包介绍可以参考&#xff1a;Python 处理 PDF 的神器 -- PyMuPDF import fitz # pip install PyMuPDF# PDF转换为IMG统一管理 def pdf_to_images(pdf_path, img_path, filename):"""pdf_p…...

分布式版本控制工具 git

git 是什么 分布式版本控制工具。github 是代码托管平台。 git 有什么用 保存文件的所有修改记录。使用版本号&#xff08;sha1 哈希值&#xff09; 进行区分。随时可浏览历史版本记录。可还原到历史指定版本。对比不同版本的文件差异。 为什么要使用 git 多人协作开发一个大…...

Flutter 中的 ExpansionTile 小部件:全面指南

Flutter 中的 ExpansionTile 小部件&#xff1a;全面指南 在 Flutter 应用中&#xff0c;ExpansionTile 是一个常用的折叠列表项&#xff0c;它允许用户点击标题来展开或折叠更多的内容。这个组件在实现可折叠列表、FAQ 部分或显示详情信息时非常有用。本文将详细介绍 Expansi…...

二进制的协议的测试程序

一、引子 由于要调试二进制私有协议&#xff0c;不想用C重头到尾写&#xff0c;用C写工程量有点大&#xff0c;因此想找一个比较简单的工具&#xff0c;postman无法实现&#xff0c;外界的几乎找不到合适的工具&#xff0c;只能考虑手写一个。 前面写了一个python通过tcp协议发…...

多线程事务

一、业务场景 我们在工作中经常会到往数据库里插入大量数据的工作&#xff0c;但是既需要保证数据的一致性&#xff0c;又要保证程序执行的效率。因此需要在多线程中使用事务&#xff0c;这样既可以保证数据的一致性&#xff0c;又能保证程序的执行效率。但是spring自带的Trans…...

MCP Server生产级配置:Playwright与LLM集成的避坑指南

1. 这不是又一个“Playwright入门教程”&#xff0c;而是一份能直接塞进CI流水线的MCP Server生产级配置实录你有没有遇到过这样的场景&#xff1a;团队刚决定用AI驱动自动化测试&#xff0c;技术选型会上大家一致看好Playwright MCP&#xff08;Model Context Protocol&#…...

本地柴油发电机组排行2023年最新榜单

柴油发电机是通过燃烧柴油驱动发动机&#xff0c;进而发电的设备&#xff0c;广泛应用于电力中断或无电网地区。1. 柴油发电机的核心工作原理是什么&#xff1f;柴油发电机是一种将化学能转化为电能的设备&#xff0c;其核心是柴油发动机与交流发电机的组合。当柴油在发动机内燃…...

Office RibbonX Editor:让Office界面定制变得像搭积木一样简单

Office RibbonX Editor&#xff1a;让Office界面定制变得像搭积木一样简单 【免费下载链接】office-ribbonx-editor An overhauled fork of the original Custom UI Editor for Microsoft Office, built with WPF 项目地址: https://gitcode.com/gh_mirrors/of/office-ribbon…...

数组专项(一):数组排序、去重、查找

大家好,欢迎来到《算法面试60讲(2026最新版全真题带解析)》第19篇!上一篇我们彻底吃透了字符串专项的核心难点——BF暴力匹配与KMP高效匹配算法,搞定了字符串模块面试最难的算法考点。从本节课开始,我们正式进入算法面试第一高频模块:数组专项。 在算法面试中,数组是出…...

Unity主题系统设计:状态驱动的主题抽象与自动注入方案

1. 这不是换个颜色那么简单&#xff1a;为什么Unity项目里“换肤”总在发布前夜崩盘&#xff1f;你有没有经历过这样的场景&#xff1a;美术同学凌晨两点发来一套新主题资源包&#xff0c;UI设计师说“这次配色更符合品牌调性”&#xff0c;产品说“上线前必须支持深色模式”&a…...

别再只测accuracy!DeepSeek集成测试必须监控的5个隐性指标(P99首token延迟、context bleed率、tool-call schema漂移)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek集成测试的核心范式演进 DeepSeek大模型的工程化落地对集成测试提出了全新挑战&#xff1a;传统基于接口响应码与字段校验的测试范式已难以覆盖语义一致性、推理链鲁棒性、上下文敏感度等高阶质…...

Unity Visual Scripting不是拖拽玩具:中阶开发者的编程范式重构指南

1. 为什么Unity官方Visual Scripting不是“拖拽完就能跑”的玩具&#xff0c;而是一套需要重新理解的编程范式很多人第一次点开Unity的Visual Scripting&#xff08;VS&#xff09;面板时&#xff0c;看到那些五颜六色的节点和丝滑的连线&#xff0c;下意识觉得&#xff1a;“这…...

yolo视频识别 车辆速度估计识别 yolo11视频实时速度测量与测速估计

文章目录YOLOv11&#xff1a;视频实时速度测量与测速估计一、YOLOv11概述二、速度测量原理三、距离测量方法四、应用场景五、实践案例以下是关于使用YOLOv11进行视频实时速度测量与测速估计的介绍&#xff1a; YOLOv11&#xff1a;视频实时速度测量与测速估计 随着计算机视觉…...

【C++】零基础入门 · 第 4 节:循环结构(while、for、do-while)

上一节我们学习了条件判断&#xff0c;这一节来学习循环结构。循环让程序能够重复执行某段代码&#xff0c;直到满足特定条件为止。C 提供了三种循环语句&#xff1a;while、for 和 do-while。 1. while 循环&#xff1a;先判断后执行 while 循环在每次执行前先检查条件&#x…...

Fiddler手机断网真相:TLS握手与证书固定的协议级拦截

1. 为什么Fiddler一开&#xff0c;手机就断网&#xff1f;这不是配置问题&#xff0c;是协议层的“信任危机”Fiddler抓包手机流量&#xff0c;本该是移动开发、测试、安全分析中最基础的操作之一。但几乎每个刚上手的人&#xff0c;都会在第二天早上发现&#xff1a;手机Wi-Fi…...