简易网络聊天室:2024/3/7

思维导图

基于UDP的简易网络聊天室

服务器:

#include <myhead.h>#define SER_PORT 8888struct msgTyp  //存储消息的结构体
{char type; 		  //消息类型char name[30];    //用户姓名char text[1024];  //消息正文
};//创建链表存储客户端信息
typedef struct node
{//数据域struct sockaddr_in cin;//指针域,存储下一个节点的地址struct node *next;
}*LinkList, Node;//创建链表节点
LinkList Create()
{LinkList s=(LinkList)malloc(sizeof(Node));if(s==NULL)return NULL;//创建成功memset(&s->cin,0,sizeof(s->cin));s->next=NULL;//表示创建新节点指针域为空return s;
}int do_login(struct msgTyp msg, int sfd, struct sockaddr_in cin, LinkList head)
{//转发登录信息LinkList p = head;while(p != NULL){sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&(p->cin), sizeof(p->cin));p = p->next;}//将当前登录的用户的地址信息结构体存储起来LinkList s = Create();//新节点数据域即为它的地址信息结构体s->cin = cin;s->next=head->next;head->next=s;return 0;
}int do_chat(LinkList head, int sfd, struct msgTyp msg, struct sockaddr_in cin)
{//转发群聊信息LinkList p = head;while(p != NULL){if(p->cin.sin_port != cin.sin_port)   //端口号不一样说明不是同一个客户端,则将消息发给其他人{sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&(p->cin), sizeof(p->cin));}p = p->next;}return 0;
}int do_quit(LinkList head, int sfd, struct msgTyp msg, struct sockaddr_in cin)
{//转发离线信息LinkList p = head;while(p->next != NULL){if(p->cin.sin_port != cin.sin_port){p = p->next;sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&(p->cin), sizeof(p->cin));}else	//将离线的客户端的地址信息结构体从链表中删除{LinkList del = p->next;p->next = del->next;free(del);del = NULL;}}return 0;
}int main(int argc, const char *argv[])
{//判断是否外部传参if(argc != 2){printf("请输入IP地址!!!\n");return -1;}//创建套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(sfd < 0){perror("socket");return -1;}printf("socket create success\n");//填充服务器自身的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET; 	sin.sin_port = htons(SER_PORT); 	//服务器绑定的端口号sin.sin_addr.s_addr = inet_addr(argv[1]); 	//服务器绑定的IP号//绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) ==-1){perror("bind error");return -1;}printf("bind success\n");char buf[128] = "";int res = 0;struct sockaddr_in cin; 	//存储对端地址信息结构体socklen_t addrlen = sizeof(cin);LinkList head = Create();  //创建链表头结点,存储客户端信息struct msgTyp msg;   //接收数据的结构体存储位置pid_t pid = fork();  //创建子进程if(pid > 0)  //父进程{//接收数据while(1){//接收客户端的消息res = recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, &addrlen);printf("[%s] %s\n",msg.name,msg.text);if(res < 0){perror("recvfrom error");return -1;}//根据消息的类型实行不同功能switch(msg.type){case 'L': 	do_login(msg, sfd, cin, head);break;case 'C':do_chat(head, sfd, msg, cin);break;case 'Q':do_quit(head, sfd, msg, cin);break;default:printf("error\n");break;}}}else if(0 == pid)  //子进程{//服务器可以发送系统消息msg.type = 'C';strcpy(msg.name, "系统消息");//发送数据while(1){//清空消息正文memset(msg.text, 0, sizeof(msg.text));//从终端获取数据fgets(msg.text, sizeof(msg.text), stdin);msg.text[strlen(msg.text) - 1] = 0;sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin));	}}else {perror("fork error");return -1;}//关闭所有文件描述符close(sfd);return 0;
}

客户端:

#include <myhead.h>#define SER_PORT 8888struct msgTyp  //消息结构体
{char type;      	//消息类型char name[30];  	//用户姓名char text[1024]; 	//消息正文
};int main(int argc, const char *argv[])
{//判断是否外部传参if(argc!=2){printf("请输入IP地址\n");return -1;}//创建套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(sfd ==-1){perror("socket");return -1;}printf("socket create success\n");//填充服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family 	= AF_INET; 	sin.sin_port = htons(SER_PORT); 	sin.sin_addr.s_addr = inet_addr(argv[1]);//输入上线的用户名称printf("请输入名字>>>");char name[20] = "";scanf("%s", name);getchar();//定义登录时的类型以及提示信息struct msgTyp msg_snd;msg_snd.type = 'L';strcpy(msg_snd.name, name);strcpy(msg_snd.text, "加入群聊");//发送登录信息if(sendto(sfd, &msg_snd, sizeof(msg_snd), 0, (struct sockaddr*)&sin, sizeof(sin)) ==-1){perror("sendto error");return -1;}char buf[128] = "";int res = 0;//存储对端地址信息结构体struct sockaddr_in cin;socklen_t addrlen = sizeof(cin);//定义接收消息的结构体struct msgTyp msg_rcv;//创建子进程pid_t pid = fork();if(pid > 0)  //父进程{//发送数据,发送聊天信息while(1){//客户端从终端获取消息并发送出去bzero(buf, sizeof(buf));                 //清空数组fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;msg_snd.type = 'C';strcpy(msg_snd.text, buf);if(strcmp(msg_snd.text, "quit") == 0){msg_snd.type = 'Q';strcpy(msg_snd.text, "已下线");}sendto(sfd, &msg_snd, sizeof(msg_snd), 0, (struct sockaddr*)&sin, sizeof(sin));if(strcmp(msg_snd.text, "已下线") == 0){break;}}kill(pid,SIGKILL);wait(NULL);//等待回收子进程资源}else if(0 == pid)  //子进程{//接收数据while(1){printf("\n");recvfrom(sfd, &msg_rcv, sizeof(msg_rcv), 0, NULL, NULL);printf("[%s] : %s", msg_rcv.name, msg_rcv.text);}}else{perror("fork error");return -1;}//关闭文件描述符close(sfd);return 0;
}

效果图:

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

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

相关文章

JavaWeb04-Request,Response

目录 一、Request&#xff08;请求&#xff09; 1.作用 2.继承体系 3.获取请求数据 &#xff08;1&#xff09;请求行 &#xff08;2&#xff09;请求头 &#xff08;3&#xff09;请求体&#xff08;POST&#xff09; &#xff08;5&#xff09;Request通用方式获取请求…

外包干了一周,技术明显倒退。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

【中高级】Java求职技能清单(2024版)

一、Java基础扎实&#xff08;反射、集合、IO、NIO、多线程、设计模式、通信协议等基础技术&#xff09; &#xff08;一&#xff09;Java &#xff08;二&#xff09;网络IO &#xff08;三&#xff09;NIO模型 &#xff08;…

项目经理如何应对多系统对接的项目?

对于项目经理来说&#xff0c;处理系统对接&#xff08;API对接&#xff09;的需求是一项既复杂又关键的任务。这项任务涉及到确保不同的系统能够高效、安全地共享数据&#xff0c;从而实现流畅的业务流程和提高整体的系统性能。下面是一个详细的指南&#xff0c;旨在帮助产品经…

海格里斯HEGERLS助力服装业领域数智化转型 配备7000个托盘位 仓库容量增超110%

近年来&#xff0c;用工荒成为服装制造行业的一大痛点。对此&#xff0c;整个生产体系就要不断地向智能化、自动化生产设备进行转型&#xff0c;甚至在研发设计上都要面向自动化做一些新一代服装制造业的开发。 作为较早入局物流赛道的河北沃克&#xff0c;目前已构建起以AI赋能…

学习统一的Hyper - network用于多模态MR图像合成和缺失模态的肿瘤分割

Learning Unified Hyper-Network for Multi-Modal MR Image Synthesis and Tumor Segmentation With Missing Modalities Learning Unified Hyper-Network for Multi-Modal MR Image Synthesis and Tumor Segmentation With Missing Modalities背景贡献实验方法多模态合成方法超…

工业制氧机的使用与维护管理指南

工业制氧机是工业生产中不可或缺的重要设备&#xff0c;其高效稳定的供氧功能对于保障生产过程的顺利进行至关重要。为了确保工业制氧机能够持续高效地提供氧气&#xff0c;正确的使用方法和维护措施是必不可少的。 在使用工业制氧机时&#xff0c;我们首先要确保设备放置在通风…

Java定时调度:Timer类和TimerTask类

Java提供了多种方式来执行定时任务&#xff0c;其中使用Timer类和TimerTask类是一种简单而有效的方法。这篇教程将介绍如何使用Java的Timer类和TimerTask类来实现定时调度。 1. Timer类 Timer类用于安排指定的任务按指定的时间执行。它可以执行一次性任务&#xff0c;也可以按…

【C语言】linux内核napi_gro_receive和netif_napi_add

napi_gro_receive 一、注释 // napi_gro_receive是网络设备接口的一个函数&#xff0c;它被NAPI&#xff08;New API&#xff09;网络轮询机制使用&#xff0c;用于接收和处理接收到的数据包。 // 这个函数通过通用接收分组&#xff08;GRO&#xff0c;Generic Receive Offlo…

一周学会Django5 Python Web开发-Django5新增视图CreateView

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计29条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Git你必须知道的知识

一&#xff1a;使用Git的原因 我们在写版本的时候&#xff0c;可能会谢谢改改&#xff0c;可能要回到之前的文件&#xff0c;修改之前的文件&#xff0c;因此总是要保持很多个文件&#xff0c;且书写文件名也很麻烦。git可以有一个仓库&#xff0c;版本库&#xff0c;可以保存这…

mysql数据库入门到精通-Windows版本mysql安装(1)

文章目录 一、数据库介绍1.1、数据库概念1.2、为什么要使用数据库1.3、关系型数据库与非关系型数据库1.4、数据库术语1.5、mysql下载及地址 二、安装mysql数据库三、mysql的管理工具3.1、mysql command line client使用 四、SQL结构化查询语言4.1、SQL概述4.2、SQL发展4.3、SQL…