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;
}
相关推荐
安步当歌1 小时前
【WebRTC】视频发送链路中类的简单分析(下)
网络·音视频·webrtc·视频编解码·video-codec
米饭是菜qy1 小时前
TCP 三次握手意义及为什么是三次握手
服务器·网络·tcp/ip
yaoxin5211232 小时前
第十九章 TCP 客户端 服务器通信 - 数据包模式
服务器·网络·tcp/ip
鹿鸣天涯2 小时前
‌华为交换机在Spine-Leaf架构中的使用场景
运维·服务器·网络
星海幻影2 小时前
网络基础-超文本协议与内外网划分(超长版)
服务器·网络·安全
WeeJot嵌入式2 小时前
网络百问百答(一)
网络
湖南罗泽南2 小时前
p2p网络介绍
网络·网络协议·p2p
有梦想的咕噜2 小时前
Secure Shell(SSH) 是一种网络协议
运维·网络协议·ssh
IPdodo全球网络3 小时前
解析“ChatGPT网络错误”:从网络专线到IP地址的根源与解决方案
网络·tcp/ip·chatgpt
腾科张老师4 小时前
为什么要使用Ansible实现Linux管理自动化?
linux·网络·学习·自动化·ansible