UDP实现群聊通信

服务器端

#include <myhead.h>
#define UDPIP "192.168.115.92"
#define UDPPORT 6666
//存储客户信息的链表结构体
typedef struct Node
{
	char name[20];
	struct sockaddr_in cin;
	struct Node *next;
}*linklist;
//数据结构体
struct data_cli
{
	char type;
	char name[20];
	char text[128];
};
//创建节点
linklist create_space()
{
	linklist s=(linklist)malloc(sizeof(struct Node));
	if(NULL==s)
		return NULL;
	bzero(s->name,sizeof(s->name));
	s->next=NULL;
	return s;
}
//末尾插入信息
linklist Insert_end(linklist head,struct sockaddr_in cin,char name[20])
{
	//创建节点
	linklist s=create_space();
	s->cin=cin;
	strcpy(s->name,name);
	//判断之前是否有节点
	if(NULL==head)
	{
		head=s;
		return head;
	}
	linklist p=head;
	while((p->next)!=NULL)
	{
		p=p->next;
	}
	p->next=s;
	//未尾插入
	return head;

}
//删除退出客户
linklist Delete_by_ele(linklist head,in_port_t cin_port)
{
        if(NULL==head)
                return NULL;
        linklist p=head;
	if(NULL==head->next)
	{
		free(head);
		return NULL;
	}
        while(p!=NULL)
        {
	

                if(ntohs(cin_port)==ntohs(p->cin.sin_port))
                {
                        linklist del=p->next;//多个字节
                        p->cin=del->cin;
			strcpy(p->name,del->name);
                        p->next=del->next;
                        free(del);del=NULL;
			return head;
                }
		if(p->next->next==NULL)
		{
			linklist q=p->next;
			free(q);
			p->next=NULL;
			return head;
		}
                p=p->next;
        }
	return head;

}


int main(int argc, const char *argv[])
{
	//创建头指针
	linklist head=NULL;
	//1.创建套接字文件
	int tfd;
	if((tfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
	{
		perror("socket");
		return -1;
	}
	//2.绑定IP和端口
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(UDPPORT);
	sin.sin_addr.s_addr=inet_addr(UDPIP);
	if(bind(tfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("bind");
		return -1;
	}
	printf("bind success\n");
	//io多路复用信息
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(tfd,&readfds);
	int maxfd=tfd;
	//3.收发信息
	struct sockaddr_in cin1;
	cin1.sin_family=AF_INET;
	socklen_t len=sizeof(cin1);
	char buf[128]="";
	int res;
	struct data_cli cli_data;
	while(1)
	{
		tempfds=readfds;
		//等待唤醒条件
		res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(res<0)
		{
			perror("select");
			return -1;
		}
		else if(res==0)
		{
			printf("超时\n");
			return -1;
		}
		if(FD_ISSET(0,&tempfds))
		{
			
			//系统向所有客户端发消息
			bzero(&cli_data,sizeof(struct data_cli));
			strcpy(cli_data.name,"系统消息:");
			fgets(cli_data.text,sizeof(cli_data.text),stdin);
       			cli_data.text[strlen(cli_data.text)-1]=0;
			linklist p=head;
			while(p!=NULL)
			{
				sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);
				p=p->next;
			}
			printf("系统发送消息成功\n");

		}
		if(FD_ISSET(tfd,&tempfds))
		{
			bzero(&cli_data,sizeof(struct data_cli));
			recvfrom(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&cin1,&len);
			switch(cli_data.type)
			{
				case 'D':
					{
	  		                        strcpy(cli_data.text,"上线了");
                                                linklist p=head;
                                                while(p!=NULL)
                                                {
                                                sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);
                                                p=p->next;
                                                }

						head=Insert_end(head,cin1,cli_data.name);
			printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"登录成功");

					}
					break;
				case 'S':
					{

						linklist p=head;
						while(p!=NULL)
						{
									if(p->cin.sin_port==cin1.sin_port)
									{
										if(p->next!=NULL)
										{
										p=p->next;
										}else{break;}
									}
							sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);
							p=p->next;
						}
			printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"客户端发送消息");
		
					}
					break;
				case 'Q':
					{

						head=Delete_by_ele(head,cin1.sin_port);
	  		                        strcpy(cli_data.text,"下线了");
                                                linklist p=head;
                                                while(p!=NULL)
                                                {
                                                sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);
                                                p=p->next;
                                                }
			printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"客户端退出");
				
					}
					break;
			}


		}

	}
	//4.关闭文件
	close(tfd);
	return 0;
}

客户端
 

#include <myhead.h>
#define IP "192.168.115.92"
#define PORT 6666
//定义信息结构体
struct data_cli
{
	char type;
	char name[20];
	char text[128];
};
int main(int argc, const char *argv[])
{
	
	//1.创建套接字
	int cfd;
	cfd=socket(AF_INET,SOCK_DGRAM,0);
	if(cfd==-1)
	{
		perror("socket");
		return -1;
	}
	//io多路复用信息
        fd_set readfds,tempfds;
        FD_ZERO(&readfds);
        FD_SET(0,&readfds);
        FD_SET(cfd,&readfds);
        int maxfd=cfd;

	//3.收发数据
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);
	socklen_t len=sizeof(struct sockaddr_in);
	//创建账户
	struct data_cli cli_data;
	bzero(&cli_data,sizeof(struct data_cli));
	printf("请登录用户:");
	cli_data.type='D';
	fgets(cli_data.name,sizeof(cli_data.name),stdin);
	cli_data.name[strlen(cli_data.name)-1]=0;
	char myname[20]="";
	strcpy(myname,cli_data.name);
	sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);
	char buf[256]="";
	int res;
	while(1)
	{
                tempfds=readfds;
                //等待唤醒条件
                res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
                if(res<0)
                {
                        perror("select");
                        return -1;
                }
                else if(res==0)
                {
                        printf("超时\n");
                        return -1;
                }
		if(FD_ISSET(0,&tempfds))
		{
			bzero(&cli_data,sizeof(struct data_cli));
			cli_data.type='S';
			strcpy(cli_data.name,myname);
			fgets(cli_data.text,sizeof(cli_data.text),stdin);
			cli_data.text[strlen(cli_data.text)-1]='\0';
			if(strcmp("quit",cli_data.text)==0)
			{
				cli_data.type='Q';
				sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);
				break;
			}
			sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);
		}
		if(FD_ISSET(cfd,&tempfds))
		{
			bzero(buf,sizeof(buf));
			bzero(&cli_data,sizeof(struct data_cli));
			recvfrom(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,&len);
			sprintf(buf,"[%s]:%s",cli_data.name,cli_data.text);
			printf("%s\n",buf);
		}
	}
	//4.关闭
	close(cfd);
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从 0 到 1 开发一个 node 命令行工具

G2 5.0 推出了服务端渲染的能力&#xff0c;为了让开发者更快捷得使用这部分能力&#xff0c;最写了一个 node 命令行工具 g2-ssr-node&#xff1a;用于把 G2 的 spec 转换成 png、jpeg 或者 pdf 等。基本的使用如下&#xff1a; $ g2-ssr-node g2png -i ./bar.json -o ./bar.…

【Web】BJDCTF 2020 个人复现

目录 ①easy_md5 ②ZJCTF&#xff0c;不过如此 ③Cookie is so subtle! ④Ezphp ⑤The Mystery of IP ①easy_md5 ffifdyop绕过SQL注入 sql注入&#xff1a;md5($password,true) 右键查看源码 数组绕过 ?a[]1&b[]2 跳转到levell14.php 同样是数组绕过 param1[…

Jmeter-分布式压测(远程启动服务器,windows)

1 前提条件 JDK已部署&#xff0c;版本一致Jmeter已部署&#xff0c;版本一致多台服务器连接的同一网络(例如&#xff1a;同一wifi)防火墙处于关闭状态&#xff08;或者对应默认端口处于开放状态&#xff09;虚拟网络适配器都处于关闭状态查找到每一台服务器的IP 2 主服务器配…

深信服AD负载均衡频繁掉线故障分析

一个由114.114.114.114引起的AD异常 客户反馈深信服负载均衡链路频繁掉线&#xff0c;具体故障现象如下 可以获取到IP地址、网关 两分钟掉一次&#xff0c;持续一个多月&#xff0c;求IT的心理阴影面积&#xff01; 链路监视器只设置了一个114.114.114.114 处理流程&#xff…

【古月居《ros入门21讲》学习笔记】12_服务端Server的编程实现

目录 说明&#xff1a; 1. 服务模型 说明 2. 实现过程&#xff08;C&#xff09; 创建服务器代码&#xff08;C&#xff09; 配置服务器代码编译规则 编译 运行 3. 实现过程&#xff08;Python&#xff09; 创建服务器代码&#xff08;Python&#xff09; 运行效果 说…

springboot3.2 整合 mybatis-plus

springboot3.2 整合 mybatis-plus springboot3.2 正式发布了 迫不及待地的感受了一下 结果在整个mybatis-plus 的时候遇到了如下报错 java.lang.IllegalArgumentException: Invalid value type for attribute factoryBeanObjectType: java.lang.String. ____ _ …

Springboot实现增删改差

一、包结构 二、各层代码 (1)数据User public class User {private Integer id;private String userName;private String note;public User() {super();}public User(Integer i, String userName, String note) {super();this.id i;this.userName userName;this.note note;…

Databend 开源周报第 121 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 支持追加流 Da…

springboot 外部化配置

背景:修改jar包中的配置比较麻烦 项目部署的时候放一个配置文件在jar包外 配置文件优先级: 1.jar包内的application.properties/yaml 2.jar包内的application-{profile}.properties/yaml 3.jar包外的application.properties/yaml 4.jar包外的application-{profile}.properties…

Linux ps命令详解:如何查看进程的PID、占用的CPU和内存使用率、虚拟内存大小等信息(附实例教程和注意事项)

Linux ps命令介绍 Linux ps命令&#xff0c;全称为process status&#xff0c;是一个非常实用的命令&#xff0c;用于显示当前进程的状态。它的功能类似于Windows的任务管理器。通过ps命令&#xff0c;我们可以查看到进程的PID、占用的CPU和内存使用率、虚拟内存大小、实际内存…

SpringBoot整合MongoDB: 构建高效的数据存储应用

文章目录 1. 引言2. MongoDB简介3. 准备工作4. SpringBoot中配置MongoDB5. 创建MongoDB实体类6. 使用Spring Data MongoDB进行数据操作7. 编写Service层8. 控制器层9. 测试10. 拓展10.1. 复杂查询10.2. 数据分页10.3. 索引优化 11. 总结 &#x1f389;SpringBoot整合MongoDB: 构…

springboot 自定义starter逐级抽取

自定义starter 背景:各个组件需要引入starter 还有自己的配置风格 –基本配置原理 &#xff08;1&#xff09;自定义配置文件 导入配置可以在配置文件中自动识别&#xff0c;提示 导入依赖后可以发现提示 &#xff08;2&#xff09;配置文件实现 –让配置文件对其他模块生…

WebUI自动化学习(Selenium+Python+Pytest框架)003

1.元素操作 在成功定位到元素之后&#xff0c;我们需要对元素进行一些操作动作。常用的元素操作动作有&#xff1a; &#xff08;1&#xff09;send_keys() 键盘动作&#xff1a;向浏览器发送一个内容&#xff0c;通常用于输入框输入内容或向浏览器发送快捷键 &#xff08;2…

九、LuaTable(表)

文章目录 一、定义二、Table(表)的构造三、Table 操作&#xff08;一&#xff09;Table连接&#xff08;二&#xff09;插入和移除&#xff08;三&#xff09;Table 排序&#xff08;四&#xff09;Table 最大值 一、定义 table 是 Lua 的一种数据结构用来帮助我们创建不同的数…

Mysql中的引擎介绍(InnoDB,MyISAM,Memory)

MySQL引擎就是指表的类型以及表在计算机上的存储方式。 MySQL数据库及其分支版本主要的存储引擎有三种&#xff0c;分别是 InnoDB、MyISAM、 Memory&#xff0c;还有一些其他的&#xff0c;CSV、Blackhole等&#xff0c;比较少见&#xff0c;可以使用SHOW ENGINES语句来查看。结…

揭开 BFC 的神秘面纱:前端开发必知必会

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Vue3的transition标签以及animate.css使用详解

一&#xff1a;前言 在项目开发中&#xff0c;有一种特殊情况是使用动画过渡去完成某个效果。比如淡入淡出&#xff0c;或者在动画完成后执行某些操作等。在以前开发中我们通常会选择使用 CSS3 进行研发。但是这样会有很多不好的地方&#xff0c;比如最原始化的封装&#xff0c…

Spring Boot实现图片上传和展示

Spring Boot实现图片上传和展示 本文将介绍如何使用Spring Boot框架搭建后端服务&#xff0c;实现接收前端上传的图片并保存到resources/images目录下。同时&#xff0c;我们还将展示如何在前端编写一个HTML页面&#xff0c;实现上传图片和从resources/images目录下获取图片并…

Minecraft Modding 模组制作-自定义方块

目录 自定义方块一般方块定义物品所属类注册方块注册方块对应物品添加材质添加各面不同的材质本地化 更多样的方块的实现方式会在之后陆续更新参考打赏 注意&#xff1a;本文代码只表现个人实现方式及习惯&#xff0c;本文解释只体现个人理解&#xff0c;不一定符合规范&#x…

【并发编程】ConcurrentHashMap底层结构和原理

&#x1f4eb;作者简介&#xff1a;小明Java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…