day39:网编day6,域套接字模型和抓包工具(聊天室小项目)

聊天室服务器:

#include 

#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__\n",__LINE__);\
	perror(msg);\
}while(0);

#define IP "192.168.114.63"
//#define IP "10.102.145.189"
#define PORT 8888

typedef struct node
{
	struct sockaddr_in sin;
	struct node *next;
}Node,*LinkList_ptr;

typedef struct msg
{
	char type;
	char name[20];
	char text[100];
}Msg;

void sendto_chat(int sfd,const char *buf,LinkList_ptr L,struct sockaddr_in cin)
{
	LinkList_ptr q=L;
	while(q->next!=NULL)
	{
		q=q->next;
		if(memcmp(&cin,&(q->sin),sizeof(cin))!=0)
		{
			if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(q->sin),sizeof(q->sin))<0)
			{
				ERR_MSG("sendto");
				return;
			}
		}
	}
}

void sendto_all(int sfd,struct sockaddr_in sin)
{
	Msg sysmsg;
	sysmsg.type='C';
	strcpy(sysmsg.name,"system");
	bzero(sysmsg.text,sizeof(sysmsg.text));
	fgets(sysmsg.text,sizeof(sysmsg.text),stdin);
	sysmsg.text[strlen(sysmsg.text)-1]=0;
	if(sendto(sfd,&sysmsg,sizeof(sysmsg),0,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("sendto");
		return;
	}
}


int  list_empty(LinkList_ptr L)
{
	if(NULL == L)
	{
		printf("所给链表不合法\n");
		return -1;
	}
	return L->next == NULL;
}

void list_delete(LinkList_ptr L)
{
	if(NULL == L || list_empty(L))
	{
		printf("头删失败\n");
		return;
	}
	LinkList_ptr q=L->next;
	L->next=L->next->next;
	free(q);
	q = NULL;
	printf("头删成功\n");
}

void sendto_system(int sfd,struct sockaddr_in sin)
{
	char buf[128]="";
	Msg climsg;
	while(1)
	{
		sendto_all(sfd,sin);
		printf("发送系统消息成功\n");
	}
}

void deal_L(int sfd,LinkList_ptr L,struct sockaddr_in cin,Msg climsg)
{
	char buf[128]="";
	LinkList_ptr p=(LinkList_ptr)malloc(sizeof(Node));
	p->next=L->next;
	L->next=p;
	bzero(buf,sizeof(buf));
	sprintf(buf,"%s玩家登录成功",climsg.name);
	p->sin=cin;
	sendto_chat(sfd,buf,L,cin);	
	printf("[%s:%d:%s]客户端连接成功\n",\
			inet_ntoa(p->sin.sin_addr),ntohs(p->sin.sin_port),climsg.name);
}

void deal_C(int sfd,LinkList_ptr L,struct sockaddr_in cin,Msg climsg)
{
	char buf[128]="";
	bzero(buf,sizeof(buf));
	sprintf(buf,"%s:%s",climsg.name,climsg.text);
	sendto_chat(sfd,buf,L,cin);
	printf("[%s:%d:%s]群聊消息发送成功\n",\
			inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),climsg.name);
}

void deal_Q(int sfd,LinkList_ptr L,struct sockaddr_in cin,Msg climsg)
{
	char buf[128]="";
	LinkList_ptr q=L;
	//找到要删除节点的上一个节点
	while(memcmp(&cin,&q->next->sin,sizeof(cin))!=0)
	{
		q=q->next;
	}
	LinkList_ptr q1=q->next;
	q->next=q->next->next;
	free(q1);
	q1=NULL;
	bzero(buf,sizeof(buf));
	sprintf(buf,"------------%s下线---------------",climsg.name);
	sendto_chat(sfd,buf,L,cin);
	printf("发送用户下线消息成功\n");
}
void ser_recvfrom(int sfd,LinkList_ptr L)
{
	ssize_t recv_len;
	char buf[128]="";
	Msg climsg;
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);
	while(1)
	{
		recv_len=recvfrom(sfd,&climsg,sizeof(climsg),0,(struct sockaddr*)&cin,&addrlen);
		if(recv_len < 0)
		{
			ERR_MSG("recvfrom");
			return ;
		}
		switch(climsg.type)
		{
		case 'L':
			deal_L(sfd,L,cin,climsg);
			break;
		case 'C':
			deal_C(sfd,L,cin,climsg);	
			break;
		case 'Q':
			deal_Q(sfd,L,cin,climsg);
			break;
		}
	}
}
void handler(int sig)
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}
int main(int argc, const char *argv[])
{
	if(signal(SIGCHLD,handler)<0)
	{
		ERR_MSG("signal");
		return -1;
	}

	//创建报式套接字
	int sfd;
	if((sfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("聊天室创建成功 sfd = %d\n",sfd);

	//填充地址信息结构体给bind使用
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT); //服务器端口号
	sin.sin_addr.s_addr = inet_addr(IP); //服务器IP

	//绑定服务器地址信息bind
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("聊天室绑定IP端口成功\n");

	//创建一个链表
	LinkList_ptr L = (LinkList_ptr)malloc(sizeof(Node));
	if(NULL == L)
	{
		ERR_MSG("create");
		return -1;
	}
	L->next=NULL;

	Msg climsg;
	pid_t pid; //创造子进程用于发送系统消息
	pid=fork();
	if(pid<0)
	{
		ERR_MSG("fork");
		return -1;
	}
	else if(0 == pid)
	{
		//子进程调用发送系统消息函数
		sendto_system(sfd,sin);
		exit(0);
	}else
	{
		//父进程调用接受消息函数
		ser_recvfrom(sfd,L);
	}

	//销毁链表
	while(!list_empty(L))
	{
		list_delete(L);
	}
	free(L);
	L=NULL;

	//关闭文件
	close(sfd);
	return 0;
}

聊天室客户端:

#include 

#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__\n",__LINE__);\
	perror(msg);\
}while(0)

#define IP "192.168.114.63"
//#define IP "10.102.145.189"
#define PORT 8888

//聊天信息结构体
typedef struct msg
{
	char type; 	//聊天类型,L登录,C聊天,Q退出
	char name[20]; //聊天室用户昵称
	char text[100]; //群聊发送的消息
}Msg;

void cli_qq_L(int cfd,struct sockaddr_in sin,Msg* pclimsg)
{
	pclimsg->type = 'L';
	printf("请输入用户昵称:");
	fgets(pclimsg->name,20,stdin);
	pclimsg->name[strlen(pclimsg->name)-1]=0;
	//发送登录请求,并让服务器保存昵称和地址信息
	if(sendto(cfd,pclimsg,sizeof(Msg),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		ERR_MSG("sendto");
		return ;
	}
	printf("发送登录请求和昵称成功\n");
}

void cli_qq_CQ(int cfd,struct sockaddr_in sin,Msg* pclimsg)
{
	char buf[100]="";
	while(1)
	{
		bzero(buf,sizeof(buf));
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;
		if(strcmp(buf,"quit")==0)
		{
			pclimsg->type='Q';
			if(sendto(cfd,pclimsg,sizeof(Msg),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
			{
				ERR_MSG("sendto");
				return ;
			}
			printf("发送退出群聊消息成功\n");
			return ;
		}else{
			pclimsg->type = 'C';
			strcpy(pclimsg->text,buf);
		}
		if(sendto(cfd,pclimsg,sizeof(Msg),0,(struct sockaddr*)&sin,sizeof(sin))<0)
		{
			ERR_MSG("sendto");
			return ;
		}
		printf("发送群聊消息成功\n");
	}
}

void cli_recvfrom(int cfd,struct sockaddr_in sin)
{
	ssize_t ret = 0;
	char buf[128]="";
	socklen_t addrlen=sizeof(sin);
	while(1)
	{
		bzero(buf,sizeof(buf));
		if((ret = recvfrom(cfd,buf,sizeof(buf),0,NULL,NULL)) < 0)
		{
			ERR_MSG("recvfrom");
			return ;
		}
		printf("%s\n",buf);
	}
}

int main(int argc, const char *argv[])
{
	//创建报式套接字
	int cfd;
	if((cfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket success cfd = %d\n",cfd);

	//非必须绑定
	//填充地址信息结构体给sendto使用
	struct sockaddr_in sin;
	socklen_t addrlen=sizeof(sin);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	Msg climsg;

	cli_qq_L(cfd,sin,&climsg);	

	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		ERR_MSG("fork");
		return -1;
	}
	else if(0 == pid)
	{
		cli_qq_CQ(cfd,sin,&climsg);
		exit(0);
	}else if(pid > 0)
	{
		cli_recvfrom(cfd,sin);	
	}
	close(cfd);
	return 0;
}

你可能感兴趣的:(tcp/ip,服务器,网络)