网络编程 day6

UDP网络聊天室

服务器:

#include <myhead.h>

//定义结构体变量存储用户信息
typedef struct{

	char type;
	char id[32];
	char text[128];
}msg_t;

//创建链表记录用户
typedef struct node_t
{
	struct sockaddr_in caddr;
	struct node_t *next;
}list;



//创建头结点
list *list_create(void){
	
	list *p = (list *)malloc(sizeof(list));
	if(p == NULL){
	
		ERR_MSG("malloc");
		return NULL;
	}
		p->next = NULL;
		return p;
}

struct sockaddr_in caddr,saddr;

void login(int sockfd,msg_t msg,list *p,struct sockaddr_in caddr){
	
	list *new = NULL;
	sprintf(msg.text,"login");
	
	while(p->next != NULL){
		
		p = p->next;
		sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));

	}
	//将新用户尾插到链表
	new = (list *)malloc(sizeof(list));
	new->caddr = caddr;
	new->next = NULL;
	p->next = new;
	return;
}

void chat(int sockfd,msg_t msg,list *p,struct sockaddr_in caddr){
	
	int n;
	while(p->next != NULL){
		
		p = p->next;
		//比较加入的是否是重复的客户端
		n = memcmp(&(p->caddr),&caddr,sizeof(caddr));
		if(n != 0){
		
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		}
	}
	return;
}

void quit(int sockfd, msg_t msg,list *p,struct sockaddr_in caddr){
	
	list *dele;
	sprintf(msg.text,"logout");
	while(p->next != NULL){
		
		if((memcmp(&(p->next->caddr),&caddr,sizeof(caddr)))== 0){
			
			dele = p->next;
			p->next = dele->next;
			free(dele);
			dele = NULL;
		}
		else{
			
			p = p->next;
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));

		}
	}
	return;

}

void *handler(void *arg){
	
	int socketfd = *(int *)arg;
	msg_t msg_s;
	strcpy(msg_s.id,"seaver");
	while(1){
	
		scanf("%[^\n]s",msg_s.text);
		getchar();
		sendto(socketfd,&msg_s,sizeof(msg_s),0,(struct sockaddr *)&caddr,sizeof(caddr));


	}
}


int main(int argc, const char *argv[])
{

	//输入服务器端口号
	if(argc != 2){
		
		printf("输入有误\n");
		return -1;
	}

	int sockfd;
	struct sockaddr_in saddr,caddr;
	socklen_t len = sizeof(caddr);
	msg_t msg;
	//创建报式套接字
	sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0){
		ERR_MSG("socket");
		return -1;
	}
	
	//填充服务器信息
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
	saddr.sin_port = htons(atoi(argv[1]));

	bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
	printf("bind success");


	list *p = list_create();
	ssize_t recvbyte;
	pthread_t tid;
	//创建线程来分线程完成任务
	pthread_create(&tid,NULL,handler,&sockfd);
	pthread_detach(tid);

	while(1){
		
		int reuse = 1;	
		//允许端口快速被复用
		setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&reuse,sizeof(reuse));
		//接收客户端信息
		recvbyte = recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&len);
		if(recvbyte < 0){
			ERR_MSG("recv");
			return -1;
		}
		
		//登录
		if(msg.type == 'L'){
			login(sockfd,msg,p,caddr);
		}
		//聊天
		else if(msg.type == 'C'){
			chat(sockfd,msg,p,caddr);
		}
		//退出
		else if(msg.type == 'Q'){
			printf("[%s %d]:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.id);
			quit(sockfd,msg,p,caddr);
		}
	}
	close(sockfd);	
	return 0;
}

 

客户端:

#include <myhead.h>

typedef struct{

	char type;
	char id[32];
	char text[128];
}msg_t;



int main(int argc, const char *argv[])
{
	if(argc != 3){

		printf("请正确输入ip地址和端口号:\n");
		return -1;
	}

	int sockfd;
	msg_t msg;
	struct sockaddr_in caddr;
	socklen_t len = sizeof(caddr);
	char buf[128];
	sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0){
		ERR_MSG("socket");
		return -1;
	}

	//填入用户的信息
	caddr.sin_family = AF_INET;
	caddr.sin_port = inet_addr(argv[2]);
	caddr.sin_addr.s_addr = htons(atoi(argv[1]));

	//封装用户信息进结构体给send函数使用,传给服务器
	printf("请输入你的名字>>>");
	scanf("%[^\n]s",msg.id);
	while(getchar()!=10);

	if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len))
		ERR_MSG("send");


	//创建进程,父进程负责接收,子进程负责从终端获取内容
	pid_t pid;
	pid = fork();

	if(pid<0)
		ERR_MSG("fork");

	else if(pid == 0){

		//子进程负责发送消息
		while(1){

			fgets(msg.text,sizeof(msg.text),stdin);
			(msg.text)[sizeof(msg.text)-1] = 0;

			if(strcmp(msg.text,"quit") == 0){
				msg.type = 'Q';

				sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len);
				kill(getppid(),SIGKILL);
				wait(NULL);
				exit(-1);
			}
			else{

				msg.type = 'C';
			}
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len);		
		}
	}

	//父进程循环接收消息
	int recv;
	while(1){
	
		recv = recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
		
		if(recv < 0){
		ERR_MSG("recvfrom");
		return -1;
		}
		printf("%s:%s\n",msg.id,msg.text);
	}
	wait(NULL);
	close(sockfd);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值