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;
}
相关推荐
缘友一世2 分钟前
java实现网络IO高并发编程java AIO
java·网络·python
dog2501 小时前
TCP off-path exploits(又一个弄巧成拙的例子)
网络·网络协议·tcp/ip
hgdlip1 小时前
ip归属地是什么意思?ip归属地是实时定位吗
网络·tcp/ip·web安全
tjjingpan1 小时前
HCIA-Access V2.5_6_3_GPON组网保护
网络
云计算DevOps-韩老师1 小时前
【网络云计算】2024第52周-每日【2024/12/26】小测-理论&实操-备份MySQL数据库并发送邮件-解析
linux·开发语言·网络·数据库·mysql·云计算·perl
IT 古月方源1 小时前
ensp ppp 协议的讲解配置
运维·网络·网络协议·tcp/ip·智能路由器
zr5268554473 小时前
IEC103 转 ModbusTCP 网关(三格电子)
运维·服务器·网络
大丈夫立于天地间3 小时前
IPv6的地址类型
网络·网络协议·学习·华为·信息与通信
hao_wujing4 小时前
Cilium:BPF 和 XDP 参考指南(2021)
网络
7ACE4 小时前
TCP Analysis Flags 之 TCP Out-Of-Order
网络协议·tcp/ip·wireshark