基于UDP的网络聊天室

客户端

#include <myhead.h>
//定义存储信息结构体
typedef struct _MSG
{char code;  //操作码:'L'表示登录'C表示群聊'S'表示系统消息'S'表示退出char name[128];  char txt[256];}msg_t;//定义保存客户端网络信息的链表
typedef struct _ADDR
{struct sockaddr_in cin;struct _ADDR* next;
}addrlist_t;//登录操作的函数
void do_login(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//先遍历链表 将新用户加入群聊的消息发送给所有人addrlist_t* tmp = addr;  //记录链表头结点while(tmp->next != NULL){tmp = tmp->next;if(sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&(tmp->cin),sizeof(tmp->cin)) == -1){perror("sendto error");return;}}//将新用户的网络信息结构体头插入链表addrlist_t* pnew = NULL;if(NULL == (pnew = (addrlist_t*)malloc(sizeof(addrlist_t)))){printf("malloc error\n");return;}pnew->cin = cin;pnew->next = addr->next;addr->next = pnew;printf("%s已上线\n",msg.name);return;
}//群聊操作函数
void do_chat(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//遍历链表,将群聊消息发给除自己以外其他人addrlist_t* ptmp = addr;while(ptmp->next != NULL){ptmp = ptmp->next;if(memcmp(&cin, &(ptmp->cin), sizeof(cin))){//说明不是自己就发送数据if(sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&(ptmp->cin),sizeof(ptmp->cin)) == -1){perror("sendto error");return;}}}return;
}//退出操作的函数
void do_quit(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//遍历链表 是自己就将自己在链表中删除,不是自己就发送退出群聊的数据addrlist_t* ptmp = addr;addrlist_t* del = NULL;while(ptmp->next != NULL){if(memcmp(&(ptmp->next->cin), &cin, sizeof(cin))){//不是自己ptmp = ptmp->next;if((sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(ptmp->cin),sizeof(ptmp->cin))) == -1){perror("sendto error");return;}}else{del = ptmp->next;ptmp->next = del->next;free(del);del=NULL;}}printf("%s已下线\n",msg.name);return;
}
int main(int argc, const char *argv[])
{if(argc != 3){   //输入ip地址及端口号,进行判断printf("input error\n");printf("usage: %s <IP> <PORT>\n",argv[0]);return -1;}//定义用于接收等待套接字int sfd;if((sfd = socket(AF_INET,SOCK_DGRAM,0)) == -1){perror("socket error");return -1;}printf("socket sfd success\n");//设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口号快速重用_%d_%s_%s_\n",__LINE__,__FILE__,__func__);//绑定(填充服务器信息结构体)struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port   = htons(atoi(argv[2]));sin.sin_addr.s_addr = inet_addr(argv[1]);socklen_t seraddr_len = sizeof(sin);if((bind(sfd, (struct sockaddr*)&sin, seraddr_len)) == -1){perror("bind error");return -1;}printf("bind success\n");//定义客户端网络信息结构体struct sockaddr_in cin;socklen_t cliaddr_len = sizeof(cin);msg_t msg;  //定义接收信息的变量msgpid_t pid;  //进程号pid = fork();  //创建多进程if(pid < 0){perror("fork error");return -1;}else if(pid == 0){   //子进程,用来收发数据//创建保存客户端信息的链表头结点addrlist_t* addr;if(NULL == (addr = (addrlist_t*)malloc(sizeof(addrlist_t)))){printf("malloc error\n");return -1;}memset(addr, 0, sizeof(addr));addr->next = NULL;while(1){  //循环收发数据memset(&msg,0,sizeof(msg));  //每次接收新用户数据清空memset(&cin,0,sizeof(cin)); //接收客户端发送的消息,存放在msg中if((recvfrom(sfd, &msg,sizeof(msg), 0,(struct sockaddr*)&cin, &cliaddr_len)) == -1){perror("recvfrom error\n");return -1;}switch(msg.code){  //判断消息中的操作码,根据操作码执行对应操作case 'L':   //登录操作do_login(sfd,msg,addr,cin);break;case 'C':   //群聊操作do_chat(sfd,msg,addr,cin);break;case 'Q':   //退出操作do_quit(sfd,msg,addr,cin);break;}}}else{//父进程,用来发送系统消息//向子进程发送群聊消息strcpy(msg.name, "系统消息");msg.code = 'C';while(1){memset(msg.txt, 0,sizeof(msg.txt));fgets(msg.txt, 256,stdin);  //终端获取接收消息msg.txt[strlen(msg.txt)-1] = '\0';if((sendto(sfd,&msg,sizeof(msg),0 ,(struct sockaddr*)&sin,seraddr_len)) == -1){perror("sendto error");return -1;}}}close(sfd);return 0;
}

服务器

#include <myhead.h>
typedef struct _MSG
{char code; //操作码:'L'表示登录'C'表示群聊'S'表示系统内存出错'S'表示系统消息char name[128];char txt[256];
}msg_t;   //定义消息结构体类型int main(int argc, const char *argv[])
{if(3 != argc){  //考虑用命令行传参方式输入ip地址及端口号,先进行判断printf("input error!\n");printf("usage:%s <IP> <PORT>\n", argv[0]);return -1;}//定义通信的套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == sfd){perror("sockfd error");return -1;}//定义服务器地址信息结构体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 seraddr_len = sizeof(sin);msg_t msg;memset(&msg,0,sizeof(msg));//输入用户名printf("请输入用户名:");fgets(msg.name,45,stdin);msg.name[strlen(msg.name)-1] = '\0';msg.code = 'L';strcpy(msg.txt,"加入群聊");//给服务器发送登录信息if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,seraddr_len) == -1){perror("sendto error");return -1;}//定义父子进程并创建pid_t pid = 0;pid = fork();if(pid < 0){printf("fork error\n");return -1;}else if(pid == 0){  //子进程,循环接收并打印接收的数据while(1){if(recvfrom(sfd,&msg,sizeof(msg),0,NULL,NULL) == -1){perror("sendto error");return -1;}//打印收到的数据printf("[%s]:%s\n",msg.name, msg.txt);}}else{   //父进程循环接收终端数据并发送给客户端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.code = 'Q';strcpy(msg.txt, "退出群聊");}else{msg.code = 'C';}if(sendto(sfd,&msg,sizeof(msg), 0,(struct sockaddr*)&sin,seraddr_len) == -1){perror("sendto error");return -1;}if(strcmp(msg.txt, "退出群聊") == 0){break;}}//杀死子进程kill(pid,SIGKILL);wait(NULL);  //等待回收子进程资源}close(sfd);return 0;
}

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

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

相关文章

智能优化算法应用:基于群居蜘蛛算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于群居蜘蛛算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于群居蜘蛛算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.群居蜘蛛算法4.实验参数设定5.算法结果6.参考…

记录创建粒子的轻量级JavaScript库——particles.js(可用于登录等背景显示)

文章目录 前言一、下载particles.js二、引入particles.js并使用三、配置数据说明如有启发&#xff0c;可点赞收藏哟~ 前言 本文记录使用创建粒子的轻量级JavaScript库 particles.js 可用于登录等背景显示 一、下载particles.js 先下载particles.js库&#xff0c;放在项目libs…

【解决】使用strApi调登录接口使用jwt时,报类型“AxiosResponse<any, any>”上不存在属性“jwt”。ts any

类型“AxiosResponse<any, any>”上不存在属性“jwt”。ts(2339) any 解决办法&#xff1a; 使用类型断言(loginData as any)?.jwt 即可

Alignment of HMM, CTC and RNN-T,对齐方式详解——语音信号处理学习(三)(选修二)

参考文献&#xff1a; Speech Recognition (option) - Alignment of HMM, CTC and RNN-T哔哩哔哩bilibili 2020 年 3月 新番 李宏毅 人类语言处理 独家笔记 Alignment - 7 - 知乎 (zhihu.com) 本次省略所有引用论文 目录 一、E2E 模型和 CTC、RNN-T 的区别 E2E 模型的思路 C…

Linux(11):Linux 账号管理与 ACL 权限设定

Linux 的账号与群组 每个登入的使用者至少都会取得两个 ID&#xff0c;一个是使用者 ID(User ID &#xff0c;简称UID)、一个是群组ID (Group ID &#xff0c;简称GID)。 Linux系统上面的用户如果需要登入主机以取得 shell 的环境来工作时&#xff0c;他需要如何进行呢? 首先…

前端:实现二级菜单(点击实现二级菜单展开)

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, i…

【HTML】VScode不打开浏览器实时预览html

1. 问题描述 预览HTML时&#xff0c;不想打开浏览器&#xff0c;想在VScode中直接实时预览 2. 解决方案 下载Microsoft官方的Live Preview 点击预览按钮即可预览

Stability AI 新发布SDXL Turbo:一款实时文本到图像生成模型

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

hugging face下载dataset时候出现You must be authenticated to access it.问题解决

Cannot access gated repo for url https://huggingface.co/tiiuae/falcon-180B/resolve/main/tokenizer_config.json. Repo model tiiuae/falcon-180B is gated. You must be authenticated to access it. 参考https://huggingface.co/docs/huggingface_hub/guides/download …

基于ora2pg迁移Oracle19C到postgreSQL14

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

7Docker搭建es和kibana

一、安装es 1.拉取镜像 sudo docker pull elasticsearch:7.12.0 elasticsearch:7.12.0:我安装的版本是7.12.0&#xff0c;可以根据实际的情况安装 创建docker容器挂在的目录&#xff1a; sudo mkdir -p /opt/elasticsearch/config sudo mkdir -p /opt/elasticsearch/data s…

WordPress 粘贴图片上传插件

找了很久&#xff0c;发现一款不错的插件&#xff0c;允许我们直接粘贴图片文件并且上传到媒体库。以前的插件上传后媒体库不会显示&#xff0c;这个要显示。 启用后编辑器会有一个图标&#xff0c;如果开启&#xff0c;那么久可以截图后直接粘贴了。 学习资料源代码&#xf…