基于udp的网络聊天室

服务器端

#include <head.h>
//定义消息结构体
typedef struct Msg
{
	char code;//定义操作码:L:登录 Q:退出 C:群聊 S:系统信息
				//操作码为一个字符
	char name[45];
	char buf[256];
}msg_t;
//定义客户端信息结构体
typedef struct Addr
{
	struct sockaddr_in cin;
	struct Addr *next;
}addrlist;
//登录
void login(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
	//遍历链表,将新用户信息发送给所有人
	addrlist *t=addr;
	while(t->next!=NULL)
	{
		t=t->next;
		if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
		{
			ERR_MSG("sendto");
		}
	}
	//将新用户头插入客户端信息结构体
	addrlist *new=NULL;
	if(NULL==(new=(addrlist *)malloc(sizeof(addrlist))))
	{
		printf("malloc error\n");
		return;
	}
	new->cin=cin;
	new->next=addr->next;
	addr->next=new;
	return;
}
//群聊
void chat(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
	//遍历链表,将群聊消息发给其他人
	addrlist *t=addr;
	while(t->next!=NULL)
	{
		t=t->next;
		//不是自己,发送数据
		if(memcmp(&cin,&(t->cin),sizeof(cin)))
		{
			if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
			{
				ERR_MSG("sendto");
			}
		}
	}
}
//退出
void quit(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
	//遍历链表,是自己就将自己在链表中删除,不是发送退出的消息
	addrlist *t=addr;
	addrlist *del=NULL;
	while(t->next!=NULL)
	{
		if(memcmp(&(t->next->cin),&cin,sizeof(cin)))
		{
			//不是自己
			t=t->next;
			if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
			{
				ERR_MSG("sendto");
			}
		}else
		{
			del=t->next; 
			t->next=del->next;
			free(del);
			del=NULL;
		}
	}
	return;
}
int main(int argc, const char *argv[])
{
	if(3!=argc)
	{
		printf("input error\n");
		printf("error: %s <IP> <PORT>",argv[0]);
		return -1;
	}
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd==-1)
	{
		ERR_MSG("socker");
	}
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(atoi(argv[2]));
	sin.sin_addr.s_addr=inet_addr(argv[1]);
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		ERR_MSG("bind");
	}
	struct sockaddr_in cin;
	cin.sin_family=AF_INET;
	socklen_t socklen=sizeof(cin);
	msg_t msg;//接收消息
	pid_t pid;//进程号
	if((pid=fork())==-1)
	{
		ERR_MSG("fork");
	}
	//子进程,接收数据
	if(pid==0)
	{
		//创建保存客户端信息的链表头结点
		addrlist *addr;
		if((addr=(addrlist*)malloc(sizeof(addrlist)))==NULL)
		{
			printf("malloc error\n");
			return -1;
		}
		memset(addr,0,sizeof(addr));
		addr->next=NULL;
		while(1)
		{
			memset(&msg,0,sizeof(msg));
			memset(&cin,0,sizeof(cin));
			if(recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&socklen)==-1)
			{
				ERR_MSG("recvfrom");
			}
			printf("[%s]:%s\n",msg.name,msg.buf);
			switch(msg.code)
			{
				case 'L':
					login(sfd,msg,addr,cin);
					break;
				case 'C':
					chat(sfd,msg,addr,cin);
					break;
				case 'Q':
					quit(sfd,msg,addr,cin);
					break;
			}
		}
	}
	else if(pid>0)
	{
		//父进程,发送系统信息,msg在fack之前定义,所以父进程同样有msg
		strcpy(msg.name,"系统信息:");
		msg.code='C';
		while(1)
		{
			memset(msg.buf,0,sizeof(msg.buf));
			fgets(msg.buf,256,stdin);
			msg.buf[strlen(msg.buf)-1]='\0';
			if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
			{
				ERR_MSG("sendto");
			}
		} 
	}
	close(sfd);
	return 0;
} 

客户端

#include <head.h>
typedef struct Msg
{
	char code;//操作码:'L'表示登录,'C':群聊 'Q':退出群聊 'S':系统信息
	char name[45];
	char buf[256];
}msg_t;
int main(int argc, const char *argv[])
{
	if(3!=argc)
	{
		printf("input error\n");
		printf("error: %s <IP><PORT>\n",argv[0]);
		return -1;
	}
	int cfd=socket(AF_INET,SOCK_DGRAM,0);
	if(cfd==-1)
	{
		ERR_MSG("socket");
	}
	struct sockaddr_in sin;
	bzero(&sin,sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=htons(atoi(argv[2]));
	sin.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t socklen=sizeof(sin);
	msg_t msg; 
	bzero(&msg,sizeof(msg));
	printf("please input username:");
	fgets(msg.name,45,stdin);
	msg.name[strlen(msg.name)-1]=0;
	msg.code='L';
	strcpy(msg.buf,"加入群聊");
	if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		ERR_MSG("sendto");
	}
	pid_t pid=fork();
	if(pid<0)
	{
		ERR_MSG("fork");
	}
	else if(pid==0)
	{
		while(1)
		{
			if(recvfrom(cfd,&msg,sizeof(msg),0,NULL,NULL)==-1)
			{
				ERR_MSG("recvfrom");
			}
			printf("[%s]:%s\n",msg.name,msg.buf);
		}
	}
	else
	{
		while(1)
		{
			bzero(msg.buf,sizeof(msg.buf));
			fgets(msg.buf,256,stdin);
			msg.buf[strlen(msg.buf)-1]=0;
			if(!strcmp(msg.buf,"Q"))
			{
				msg.code='Q';
				strcpy(msg.buf,"退出群聊");
			}
			else
			{
				msg.code='C';
			}
			if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
			{
				ERR_MSG("sendto");
			}
			if(!strcmp(msg.buf,"退出群聊"))
			{
				break;
			}
		}
		kill(pid,SIGKILL);
		wait(NULL);
	}
	close(cfd);
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值