2024/4/21 UDP网络聊天室day7

#include "head.h"
//服务器端
void server_char(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
void server_login(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
void server_quit(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr);
list_t *Createlist();
int main(int argc, const char *argv[])
{
	if(argc!=3){
		printf("请输入IP地址 端口号\n");
		return -1;
	}
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0)
	{
		perror("socket error");
		return -1;
	}
	struct sockaddr_in saddr,caddr;
	saddr.sin_family=AF_INET;
	saddr.sin_port=htons(atoi(argv[2]));
	saddr.sin_addr.s_addr=inet_addr(argv[1]);
	int len=sizeof(caddr);
	if(bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))==-1){
		perror("bind error");
		return -1;
	}
	MSG_t msg;
	list_t *p=Createlist();
	while(1){//接收客户端发来的结构体,判断类型,执行相应函数
		recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,&len);
		switch(msg.type)
		{
			case login:
				server_login(sockfd,p,msg,caddr);
				break;
			case chat:
				server_char(sockfd,p,msg,caddr);
				break;
			case quit:
				server_quit(sockfd,p,msg,caddr);
				break;
		}
	}
	close(sockfd);
	return 0;
}

void server_char(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
	while(p->next!=NULL)
	{
		p=p->next;
		//当前用户结点跳过不发送信息
		if(memcmp(&(p->addr),&caddr,sizeof(caddr))==0){
			continue;
		}
		//其他用户发送信息
		sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
	}
}
void server_login(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
	sprintf(msg.text,"%s加入chat\n",msg.name);
	printf("%s\n",msg.text);
	while(p->next!=NULL)
	{//向所有链表内用户发送上线信息
		p=p->next;
		sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
	}
	//向链表添加新用户
	list_t *pnew=(list_t*)malloc(sizeof(list_t));
	pnew->next=NULL;
	p->next=pnew;
	pnew->addr=caddr;

}
void server_quit(int sockfd,list_t *p,MSG_t msg,struct sockaddr_in caddr)
{
	list_t *pdel=NULL;
	//将离线信息写入text
	sprintf(msg.text,"%s已下线\n",msg.name);
	while(p->next!=NULL)
	{
		//找到当前用户的位置删除结点
		if(memcmp(&(p->next->addr),&caddr,sizeof(caddr))==0){
			pdel=p->next;
			p->next=pdel->next;
			free(pdel);
			pdel=NULL;
		}else{//非当前用户发送离线信息
			p=p->next;
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(p->addr),sizeof(p->addr));
			}
	}


}

list_t *Createlist()
{
	list_t *p=(list_t*)malloc(sizeof(list_t));
	if(p==NULL)
	{
		perror("malloc error");
		return NULL;
	}
	p->next=NULL;
	return p;
}

#include "head.h"
//客户端
int main(int argc, const char *argv[])
{
	if(argc!=3){
		printf("请输入IP地址 端口号\n");
		return -1;
	}
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd==-1){
		perror("socket error");
		return -1;
	}
	struct sockaddr_in caddr;
	caddr.sin_family=AF_INET;
	caddr.sin_port=htons(atoi(argv[2]));
	caddr.sin_addr.s_addr=inet_addr(argv[1]);

	MSG_t msg;
	printf("请输入用户名:");
	fgets(msg.name,sizeof(msg.name),stdin);
	if(msg.name[strlen(msg.name)-1]=='\n'){
		msg.name[strlen(msg.name)-1]='\0';
	}
	msg.type=login;//发送用户名和登录类型的结构体到服务器
	sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));

	pid_t pid=fork();
	if(pid<0){
		perror("fork error");
		return -1;
	}else if(pid==0){//子进程接收服务器返回的结构体消息
		while(1){
			recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
			printf("%s:%s\n",msg.name,msg.text);
		}
	}else{//父进程向服务器发送结构体类型消息
		while(1){
			//向结构text写内容
			fgets(msg.text,sizeof(msg.text),stdin);
			
		 	if(msg.text[strlen(msg.text)-1]=='\n'){
				msg.text[strlen(msg.text)-1]='\0';
				}//在输入内容后添加\0
			
			//输入quit跳出循环下线
		 	if(strncmp(msg.text,"quit",4)==0){
				msg.type=quit;
				sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));
				break;
			}else{//非quit正常聊天
				msg.type=chat;
				
				sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&caddr,sizeof(caddr));
				}
		}
		kill(pid,SIGKILL);//循环结束说明用户下线杀死子进程
		wait(NULL);
	}
	close(sockfd);
	return 0;
}
#include <myhead.h>
//重定向list_t用户地址端口链表
typedef struct node
{
	struct sockaddr_in addr;
	struct node *next;
}list_t;
//重定向MSG_t信息结构体
typedef struct msg_t
{
	int type;
	char name[32];
	char text[128];
}MSG_t;
//定义枚举变量
enum type_t
{
	login,
	chat,
	quit,
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值