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

基于UDP的网络聊天室

项目需求:

  1. 如果有用户登录,其他用户可以收到这个人的登录信息
  2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
  3. 如果有人下线,其他用户可以收到这个人的下线信息
  4. 服务器可以发送系统信息

server.c

#include <myhead.h>
struct Node
{char usrName[20];  //用户名struct sockaddr_in cin;struct Node *next;  //指针域
};struct msgTyp
{char type;char usrName[20];char msgText[1024];
};int main(int argc,const char *argv[])
{if(argc!=3){printf("请输入IP地址和端口号\n");return -1;}//创建用于通信的服务器套接字文件描述符int sfd = socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket error");return -1;}//为套接字绑定ip地址和端口号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]);if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("bind error");return -1;} struct msgTyp buf;struct sockaddr_in cin;socklen_t addrlen = sizeof(cin);recvfrom(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);struct Node *L = (struct Node *)malloc(sizeof(struct Node));if(buf.type=='L'){strcpy(L->usrName,buf.usrName);L->cin = cin;L->next = NULL;printf("%s[%s:%d]登陆成功\n",buf.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));}//创建父子进程pid_t pid = fork();if(pid<0){perror("fork error");return -1;}if(pid==0){//子进程,用于发送系统消息while(1){memset(&buf,0,sizeof(buf));char msgText[1024]="";fgets(msgText,sizeof(msgText),stdin);msgText[strlen(msgText)-1]=0;buf.type = 'S';strcpy(buf.usrName,"**system**");strcpy(buf.msgText,msgText);//给父进程发送一个消息,在由父进程转发给用户if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}printf("%s[%s:%s]chat成功\n",buf.usrName,argv[1],argv[2]);}exit(EXIT_SUCCESS);}//父进程,用于收消息struct Node *P=L;while(1){memset(&buf,0,sizeof(buf));recvfrom(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);if(buf.type=='L')  //表示发送的是登陆信息{//遍历链表,告知其他人有人登陆了struct Node *Q=L;struct sockaddr_in sin;while(Q!=NULL){sin = Q->cin;if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}Q=Q->next;}//将信息放入链表struct Node *F = (struct Node *)malloc(sizeof(struct Node));strcpy(F->usrName,buf.usrName);F->cin = cin;F->next = NULL;P->next = F;P = F;printf("%s[%s:%d]登陆成功\n",buf.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));}else if(buf.type=='C'||buf.type=='S')   //表示发送的是聊天信息{//遍历链表,将聊天信息告诉链表中的所有人struct Node *Q=L;struct sockaddr_in sin;while(Q!=NULL){sin = Q->cin;if(strcmp(Q->usrName,buf.usrName)==0){Q=Q->next;continue;}if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}Q=Q->next;}if(buf.type=='C'){printf("%s[%s:%d]chat成功\n",buf.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));}}else if(buf.type=='Q')   //表示发送的是退出信息{//遍历链表,告知其他人此用户已经退出struct Node *Q=L;struct sockaddr_in sin;while(Q!=NULL){sin = Q->cin;if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}Q=Q->next;}//遍历链表,删除退出用户的链表信息Q=L;if(strcmp(Q->usrName,buf.usrName)==0){L=L->next;free(Q);Q=NULL;}else{while(strcmp(Q->next->usrName,buf.usrName)!=0){Q=Q->next;}struct Node *B=Q->next;Q->next = B->next;free(B);B=NULL;}}}close(sfd);return 0;
}

client.c 

#include <myhead.h>struct msgTyp
{char type;char usrName[20];char msgText[1024];
};int main(int argc,const char *argv[])
{if(argc!=3){printf("请输入IP地址和端口号\n");return -1;}//创建用于通信的服务器套接字文件描述符int cfd = socket(AF_INET,SOCK_DGRAM,0);if(cfd==-1){perror("socket error");return -1;}//给服务器发送一个登陆信息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]);char usrname[20]="";printf("请输入姓名>>>");fgets(usrname,sizeof(usrname),stdin);usrname[strlen(usrname)-1]=0;struct msgTyp buf;buf.type = 'L';strcpy(buf.usrName,usrname);if(sendto(cfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}//创建父子进程pid_t pid = fork();if(pid<0){perror("fork error");return -1;}if(pid==0){//子进程,用于发送消息while(1){memset(&buf,0,sizeof(buf));char msgText[1024]="";fgets(msgText,sizeof(msgText),stdin);msgText[strlen(msgText)-1]=0;if(strcmp(msgText,"quit")==0){buf.type = 'Q';}else{buf.type = 'C';}strcpy(buf.usrName,usrname);strcpy(buf.msgText,msgText);if(sendto(cfd,&buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin))==-1){perror("发送error");return -1;}if(buf.type == 'Q'){break;}}exit(EXIT_SUCCESS);}//父进程,用于收消息while(1){memset(&buf,0,sizeof(buf));recv(cfd,&buf,sizeof(buf),0);if(buf.type=='L')   //表示有其他人登陆了{printf("-----%s登录成功-----\n",buf.usrName);}else if(buf.type=='C'||buf.type=='S')   //表示有人发送了聊天信息{printf("%s:%s\n",buf.usrName,buf.msgText);}else if(buf.type=='Q')   //表示有人发送了退出信息{if(strcmp(buf.usrName,usrname)==0){break;}printf("-----%s 已下线-----\n",buf.usrName);}}wait(NULL);close(cfd);return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 湖南省第八届职工职业技能大赛 暨“智赋万企”数字化应用技术技能大赛 网络与信息安全管理员赛项技术文件
  • 8.15成都市计量院面试问答
  • Linux - 常用基础指令和命令
  • 脱胎于 S 语言的R语言,它何为成为各行业数据分析师的首选?
  • anolis 8.9安装k8s
  • 【C++11】右值引用的深度解析(什么是右值引用?它有什么作用?能应用在那些场景?)
  • 使用MYSQL函数问题
  • 最新图像修复论文汇总(2024年以来)(三)
  • Qt如何封装工具
  • 原型与原型链与继承
  • uniapp 日常业务 随便写写 源码
  • 嵌入式软件--模电基础 DAY 2
  • 探索数字媒体产业园区的未来之路
  • 电子秤方案低功耗蓝牙芯片CST92P15
  • 结构体和类
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • Apache的基本使用
  • C++11: atomic 头文件
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • java8-模拟hadoop
  • JavaScript类型识别
  • Java读取Properties文件的六种方法
  • Spark RDD学习: aggregate函数
  • spring boot下thymeleaf全局静态变量配置
  • ViewService——一种保证客户端与服务端同步的方法
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 反思总结然后整装待发
  • 跨域
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 深入浏览器事件循环的本质
  • Hibernate主键生成策略及选择
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​ubuntu下安装kvm虚拟机
  • ​zookeeper集群配置与启动
  • ​第20课 在Android Native开发中加入新的C++类
  • (02)Unity使用在线AI大模型(调用Python)
  • (55)MOS管专题--->(10)MOS管的封装
  • (SERIES12)DM性能优化
  • (动态规划)5. 最长回文子串 java解决
  • (二刷)代码随想录第16天|104.二叉树的最大深度 559.n叉树的最大深度● 111.二叉树的最小深度● 222.完全二叉树的节点个数
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (篇九)MySQL常用内置函数
  • (一一四)第九章编程练习
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET 发展历程
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值