手把手教你搭建 UDP 多人聊天室(附完整源码)

一、项目介绍       

        本文将分享一个基于 UDP 协议的简易多人聊天室项目,包含服务器端和客户端的完整实现。该聊天室支持多客户端同时连接,能实现消息群发、用户加入 / 退出通知等核心功能,适合作为网络编程入门实践案例。

        项目采用 C 语言开发,利用 UDP 的无连接特性实现数据传输,通过链表管理在线客户端信息,核心功能包括:

  • 服务器端:客户端连接管理、消息转发、加入 / 退出通知
  • 客户端:消息发送、实时接收、退出控制
二、核心技术点
  1. UDP 协议应用
    采用SOCK_DGRAM类型的套接字实现无连接通信,通过sendtorecvfrom函数完成数据收发,无需建立持久连接,适合简单的即时通讯场景。

  2. 链表数据结构
    服务器端使用链表存储在线客户端的 IP 和端口信息,实现客户端的动态加入 / 删除管理,通过遍历链表完成消息群发(排除发送者自身)。

  3. 多线程编程
    客户端采用主线程发送消息、子线程接收消息的设计,实现消息收发的并行处理,避免阻塞。

  4. 网络字节序转换
    使用htons/ntohsinet_addr/inet_ntoa等函数处理 IP 地址和端口的字节序转换,保证跨平台通信兼容性。

三、代码解析
1. 服务器端(server.c)
  • 数据结构设计:定义liu结构体存储客户端地址信息,通过链表头节点管理所有在线客户端

  • 核心功能函数

    • qunfa:遍历链表群发消息(排除发送者)
    • chuangjianlianbiao:新增客户端到链表并广播加入通知
    • panduan:判断客户端是否已在线
    • tuichu:处理客户端退出,从链表移除并广播退出通知
  • 主逻辑:循环接收客户端消息,根据消息类型(普通消息 / 退出指令)和客户端状态(新用户 / 老用户)执行对应操作。

#include<myhead.h>
#define IP "192.168.175.46"
#define PORT 1111
typedef struct liu 
{struct sockaddr_in addr;struct liu *next;
} xue, *pxue;
pxue toujiedian() 
{pxue p = malloc(sizeof(xue));p->next = NULL;return p;
}
void qunfa(int oldfd,pxue L,char buff[],int n,struct sockaddr_in sender)//群发消息(不发给自己)
{pxue t = L->next;while(t) {if(!(t->addr.sin_addr.s_addr==sender.sin_addr.s_addr&&t->addr.sin_port==sender.sin_port))//不发给自己{sendto(oldfd,buff,n,0,(struct sockaddr*)&(t->addr),sizeof(struct sockaddr_in));}t = t->next;}
}
void chuangjianlianbiao(int oldfd,pxue L,struct sockaddr_in client) // 添加客户端到链表并广播加入消息
{pxue p = malloc(sizeof(xue));p->addr = client;p->next = L->next;L->next = p;char str[1024];sprintf(str,"系统消息:%s:%d 加入聊天室......",inet_ntoa(client.sin_addr),ntohs(client.sin_port));int n = strlen(str);qunfa(oldfd,L,str,n,client);//调用群发函数发送新用户加入聊天室的信息
}
int panduan(pxue L, struct sockaddr_in client)// 判断客户端是否已存在
{pxue t=L->next;while(t)//t只要不是NULL就运行{if(t->addr.sin_addr.s_addr==client.sin_addr.s_addr&&t->addr.sin_port==client.sin_port) {return 0;// 已存在}t=t->next;}return 1;// 不存在
}
void tuichu(int oldfd,pxue L,struct sockaddr_in client)// 客户端退出处理 
{pxue t = L->next;pxue Q = L;while(t) {if(t->addr.sin_addr.s_addr==client.sin_addr.s_addr&&t->addr.sin_port==client.sin_port) {         char str[1024];sprintf(str,"系统消息:%s:%d 退出了聊天室......",inet_ntoa(client.sin_addr),ntohs(client.sin_port));int n = strlen(str);qunfa(oldfd,L,str,n,client);//群发退出消息  Q->next = t->next;free(t);//从链表删除return;}Q = t;t = t->next;}
}
int main(int argc,const char*argv[]) 
{int oldfd=socket(AF_INET, SOCK_DGRAM, 0);if(oldfd==-1) {perror("socket");return -1;}struct sockaddr_in server={.sin_family=AF_INET,.sin_port=htons(PORT),.sin_addr.s_addr=inet_addr(IP)};if(bind(oldfd,(struct sockaddr*)&server,sizeof(server))==-1) {perror("bind");return -1;}pxue L=toujiedian();char buff[1024];struct sockaddr_in client;int len = sizeof(client);printf("UDP聊天室服务器已启动,等待客户端连接...\n");while(1) {bzero(buff,sizeof(buff));int n=recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr*)&client, &len);//有新客户端连接或者有旧客户端发消息会触发if(n<0) {perror("recvfrom");continue;}buff[n] = '\0';if(strcmp(buff,"quit")==0)//先判断消息是否为退出指令,不进入新老客户判断{tuichu(oldfd,L,client);//如果是退出指令,直接进入退出处理函数continue;}if(panduan(L,client))//确定不是退出指令后,判断发信息的客户端是否存储在链表里{chuangjianlianbiao(oldfd, L, client);//不存在就创建并存储客户端信息,同时广播加入信息}char str[1024];bzero(str,sizeof(str));sprintf(str,"%s:%d发来:",inet_ntoa(client.sin_addr),ntohs(client.sin_port));strcat(str,buff);qunfa(oldfd,L,str,n,client);//存在就群发客户端发来的消息}close(oldfd);return 0;
}
2. 客户端(客户端 1.c)
  • 多线程设计:子线程jieshou循环接收服务器转发的消息并打印,主线程负责读取用户输入并发送。
  • 通信流程:绑定本地地址后连接服务器,输入消息自动发送,输入 "quit" 时退出聊天室并通知服务器。
#include<myhead.h>
#define IP "192.168.175.46"// 服务端IP
#define PORT 1111// 服务端端口
int oldfd;
void *jieshou()// 接收线程
{char buff[1024];struct sockaddr_in from;int len = sizeof(from);while(1) {bzero(buff, sizeof(buff));int n =recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr*)&from,&len);if(n>0) {buff[n]='\0';printf("%s\n",buff);}}
}
int main(int argc,const char*argv[]) 
{oldfd= socket(AF_INET,SOCK_DGRAM, 0);if(oldfd == -1) {perror("socket");return -1;}//绑定客户端自己的地址struct sockaddr_in client={.sin_family=AF_INET,.sin_port=htons(2222),.sin_addr.s_addr=inet_addr("192.168.175.46")};if(bind(oldfd,(struct sockaddr*)&client,sizeof(client))==-1) {perror("bind");return -1;}//要连接的服务器地址struct sockaddr_in server={.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};printf("\t\t连接到聊天室服务器 %s:%d\n",IP,PORT);printf("\t\t输入消息并回车即可发送,输入 quit 退出聊天室\n");// 创建接收线程pthread_t tid;pthread_create(&tid,NULL,jieshou,NULL);pthread_detach(tid);//告诉系统:这个线程结束后,帮我自动回收// 主线程负责发送char buff[1024];while(1) {bzero(buff, sizeof(buff));fgets(buff, sizeof(buff),stdin);buff[strlen(buff)-1] = '\0';sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr*)&server,sizeof(server));if(strcmp(buff, "quit")==0) {printf("您已退出聊天室\n");break;}}close(oldfd);return 0;
}
四、运行效果
  1. 启动服务器后,显示 "UDP 聊天室服务器已启动,等待客户端连接..."
  2. 客户端启动后,自动连接服务器并加入聊天室,其他在线用户会收到 "系统消息:IP: 端口 加入聊天室......"
  3. 任一客户端发送消息,其他客户端会收到 "IP: 端口发来:消息内容"
  4. 客户端输入 "quit",其他用户会收到退出通知,该客户端从在线列表中移除
五、总结与扩展方向

本项目实现了 UDP 聊天室的基础功能,可进一步扩展:

  • 增加用户昵称功能(替代 IP: 端口显示)
  • 实现私聊功能(指定接收者 IP 和端口)
  • 加入消息加密机制,提升安全性
  • 增加客户端心跳检测,处理异常断开情况

完整代码已附在文中,适合网络编程初学者参考学习,如有问题欢迎留言交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95353.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue基础知识-使用监视属性watch和计算属性computed实现列表过滤+排序

一、完整源码<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src…

自动化运维-ansible中的管理机密

自动化运维-ansible中的管理机密 一、Ansible Vault 在自动化配置管理中&#xff0c;直接以纯文本形式存储密码、API密钥、证书等敏感信息是极大的安全漏洞。Ansible Vault 正是为了解决这一问题而设计的核心功能 Ansible Vault 是 Ansible 的一个核心功能&#xff0c;它允许用…

UFUNCTION C++ 的再次理解

一.UFUNCTION 格式和属性也比较像&#xff0c;两部分 函数说明符&#xff0c;和元数据说明符UFUNCTION不仅能 控制对蓝图公开&#xff0c;还能与 绑定委托&#xff0c;用户输入,网络回调功能相关联&#xff0c;而且还能创建自己控制带命令二.函数说明符控制 &#xff0c;函数在…

《论文阅读》从心到词:通过综合比喻语言和语义上下文信号产生同理心反应 2025 ACL findings

《论文阅读》从心到词:通过综合比喻语言和语义上下文信号产生同理心反应 2025 ACL findings 前言 创新点 形象语言 (Figurative Language) 语义上下文信号(Semantic Context Signals) 模型架构 情绪原因标注 形象语言元数据获取 共情回复生成 实验结果 总结 趋势 前言 亲…

MySQL内置的各种单行函数

精选专栏链接 &#x1f517; MySQL技术笔记专栏Redis技术笔记专栏大模型搭建专栏Python学习笔记专栏深度学习算法专栏 欢迎订阅&#xff0c;点赞&#xff0b;关注&#xff0c;每日精进1%&#xff0c;与百万开发者共攀技术珠峰 更多内容持续更新中&#xff01;希望能给大家带来…

Python OpenCV图像处理与深度学习:Python OpenCV视频处理入门

视频处理基础&#xff1a;掌握OpenCV视频操作 学习目标 通过本课程&#xff0c;学员们将学习如何使用Python和OpenCV库来处理视频文件&#xff0c;包括读取视频、捕获摄像头视频流、处理视频帧以及保存处理后的视频&#xff0c;同时&#xff0c;能够独立完成基本的视频处理任务…

AI 赋能 Java 开发效率:全流程痛点解决与实践案例(四)

文档与注释自动化&#xff1a;从 “手动撰写” 到 “实时同步”&#xff0c;降低维护成本 &#x1f4c4; Java 开发强调 “文档先行”&#xff0c;Javadoc 注释、架构文档、接口文档是项目维护的重要资产。但手动撰写文档存在两大痛点&#xff1a;一是耗时&#xff08;开发者平…

【机器学习学习笔记】pandas基础

零基础入门 Pandas&#xff1a;数据处理的 "万能工具"如果你是刚接触数据分析的小白&#xff0c;一定听过 "Pandas" 这个名字。简单说&#xff0c;Pandas 是 Python 中专门用来处理数据的工具库&#xff0c;就像 Excel 的 "高级版"—— 能更快、…

(Mysql)MVCC、Redo Log 与 Undo Log

1. MVCC&#xff08;多版本并发控制&#xff09;概念 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种数据库并发控制机制&#xff0c;用于解决 读写冲突&#xff0c;提高数据库并发性能。MySQL InnoDB 存储引擎使用 MVCC 来实现 非阻塞读&#xff08;即…

OpenCV-Python Tutorial : A Candy from Official Main Page(五)

4.5FAST Algorithm for Corner Detection 4.5.1FAST算法 我们已了解多种特征检测器&#xff0c;其中许多效果出色。但从实时应用的角度来看&#xff0c;它们的速度仍不够快。一个典型例子是计算资源有限的SLAM&#xff08;同步定位与建图&#xff09;移动机器人。 为解决此问…

LINUX 91 SHELL:删除空文件夹 计数

问题 [rootweb ~]# find -type f -exec echo "file:{}" $path; find: 遗漏“-exec”的参数 您在 /var/spool/mail/root 中有邮件[rootweb ~]# $path/root -bash: /root: 没有那个文件或目录 您在 /var/spool/mail/root 中有新邮件 [rootweb ~]# path/root [rootweb ~…

视频软解码技术详解:原理、应用与未来发展

视频软解码的基本原理 概念解析&#xff1a;CPU主导的通用解码方式 视频软解码是一种完全依赖通用CPU执行解码算法的视频还原技术&#xff0c;其核心特征在于不依赖任何专用硬件模块&#xff0c;而是通过软件程序调用CPU的通用计算能力完成压缩视频数据的解码过程[1][2]。与硬…

线性回归中梯度下降与正规方程以及拟合问题与正则化

线性回归实战指南&#xff1a;从理论到实践 目录 线性回归理论基础机器学习项目开发流程波士顿房价预测实战梯度下降与正规方程模型评估指标拟合问题与正则化总结与展望 1. 线性回归理论基础 1.1 什么是线性回归&#xff1f; 线性回归是一种监督学习算法&#xff0c;用于预…

为什么46.1k程序员都在用这个AI绘画神器?我体验一周后终于明白了

大家好&#xff0c;我是顾北&#xff0c;一名AI应用探索者&#xff0c;也是GitHub开源项目收集者。说起AI绘画这事儿&#xff0c;我之前真的是又爱又恨。上个月想给朋友搞张生日贺图&#xff0c;结果在Stable Diffusion WebUI里折腾了大半天。采样步数&#xff1f;CFG比例&…

Java基础第8天总结(map遍历、Stream流)

选中一部分代码&#xff0c;然后CTRLALTT&#xff0c;可以在外面套上while循环,try..catch之类的小案例&#xff1a;电影信息管理模块&#xff1a;用户可以上架、查询、下架、下架某个主演参演的电影package Demo;import lombok.AllArgsConstructor; import lombok.Data; impor…

总线矩阵的原理

总线矩阵&#xff08;Bus Matrix&#xff09;是多主设备共享多从设备的智能连接与仲裁核心&#xff0c;本质是一个“灵活的交叉开关阵列”&#xff0c;用于解决多个主设备&#xff08;如CPU、DMA、GPU&#xff09;同时访问多个从设备&#xff08;如内存、外设、存储芯片&#x…

硬件开发_基于Zigee组网的果园养殖监控系统

一.系统概述 果园环境监控系统功能如下&#xff1a; 核心控制器&#xff1a;以STM32为核心控制器&#xff0c;承担整体的数据采集、处理及控制任务。环境参数监测&#xff1a;集成温度传感器、CO₂传感器、光照传感器和土壤湿度传感器&#xff0c;可实时采集果园内的温度、二氧…

K8s调度核心:从Pod分配到节点优化

在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;Pod 调度是指 K8s 系统根据特定规则和策略&#xff0c;将 Pod 合理分配到集群中的某个节点&#xff08;Node&#xff09;上运行的过程。其核心目标是确保 Pod 在合适的节点上高效、稳定地运行&#xff0c;充分利用集群资…

Tomcat 企业级运维实战系列(四):Tomcat 企业级监控

Tomcat 企业级运维实战系列&#xff08;四&#xff09;&#xff1a;Tomcat 企业级监控一&#xff1a;监控工具1&#xff09;概述2&#xff09;流程3&#xff09;部署二&#xff1a;监控命令1&#xff09;jps2&#xff09;jstack3&#xff09;jmap4&#xff09;MAT 工具分析三&a…

技术干货丨HyperMesh 新界面功能与技术升级解析

全文内容选自 Altair 区域技术交流会华东站Altair 高级技术经理 张晨《HyperWorks 2025&#xff1a;下一代建模可视化和二次开发平台》演讲1、引言今天我为大家介绍 HyperMesh——这个大家既熟悉又陌生的工具。说熟悉&#xff0c;是因为它一直是工程仿真领域的主流建模软件&…