《网络编程》基于UDP的网络聊天室8.11

发布于:2023-01-21 ⋅ 阅读:(421) ⋅ 点赞:(0)

目录

代码:

头文件myhead.h

 服务器server.c

客户端client.c

执行结果:


1. 需求
项目需求:
1. 如果有用户登录,其他用户可以收到这个人的登录信息
2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
3. 如果有人下线,其他用户可以收到这个人的下线信息
4. 服务器可以发送系统信息

 

代码:

头文件myhead.h

#ifndef __MYHEAD_H__
#define __MYHEAD_H__


#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdlib.h>
#include<wait.h>
#include<signal.h>
//打印错误信息
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__); \
	perror(msg);}while(0)

typedef struct Node
{
	struct sockaddr_in addr;
	struct Node *next;
}node;

typedef struct Msg
{
	int code;
	char user[32];
	char text[128];
}msg_t;

#endif

 服务器server.c

#include"myhead.h"

//创建节点函数
int create_node(node **phead)
{
	*phead = (node *)malloc(sizeof(node));
	if(*phead == NULL)
	{
		printf("内存分配失败\n");
		return -1;
	}
	(*phead)->next = NULL;
	return 0;
}

//尾插
int insert_tail(node *phead,struct sockaddr_in addr)
{
	if(phead == NULL)
	{
		printf("尾插错误\n");
		return -1;
	}
	node *pnew = NULL;
	create_node(&pnew);
	pnew->addr = addr;
	node *ptmp = phead;
	while(ptmp->next != NULL)
	{
		ptmp = ptmp->next;
	}
	ptmp->next = pnew;
	return 0;
}


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

	//填充服务器的IP地址以及端口号
	if(argc < 3)
	{
		fprintf(stderr,"请输入端口号\n");
		return -1;
	}
	int port = atoi(argv[2]);
	if(port<1024 || port>49151)
	{
		fprintf(stderr,"端口号错误\n");
		return -1;
	}

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);                  //端口号
	sin.sin_addr.s_addr = inet_addr(argv[1]);    //IP
	socklen_t serveraddr_len = sizeof(sin);

	//绑定服务器的地址信息结构体
	if(bind(sfd,(struct sockaddr *)&sin,serveraddr_len) == -1)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");

	struct sockaddr_in cin;
	memset(&cin,0,sizeof(cin));
	cin.sin_family = AF_INET;
	cin.sin_port = htons(port);                  //端口号
	cin.sin_addr.s_addr = inet_addr(argv[1]);    //IP
	socklen_t addrlen = sizeof(cin);


	char name[32] = {0};
	pid_t pid = fork();
	msg_t msg;
	msg_t msg_send;
	//创建头结点
	node *phead;
	create_node(&phead);
	phead->addr = cin;


	if(pid == 0)
	{
		while(1)
		{
		//接收
		memset(&msg,0,sizeof(msg));
		if(recvfrom(sfd,(void *)&msg,sizeof(msg),0,(struct sockaddr *)&cin,&addrlen) < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
		switch(msg.code){
		case 1:
			printf("[%s]玩家已上线\n",msg.user);
			insert_tail(phead,cin);
			node *q = phead->next;
			while(q != NULL)
			{
				msg.code = 1;
				if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&q->addr,sizeof(q->addr)) < 0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				q=q->next;
			}
			break;
		case 2:
			if(strcmp("管理员",msg.user) != 0)
			{
				printf("[%s]:%s\n",msg.user,msg.text);
			}
			node *p = phead->next;
			while(p != NULL)
			{
				msg.code = 2;
				if(sendto(sfd,(void *)&msg,sizeof(msg),0,(struct sockaddr*)&p->addr,sizeof(p->addr)) < 0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				p=p->next;
			}
			break;
		case 3:
			printf("[%s]:退出了\n",msg.user);
			node *t = phead;
			node *pdel = NULL;
			while(t->next != NULL)
			{
				msg.code = 3;
				if(memcmp(&(t->next->addr),&cin,sizeof(cin)) == 0)
				{
					pdel = t->next;
					t->next = pdel->next;
					free(pdel);
				}
				else{
					t=t->next;
					if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&t->addr,sizeof(t->addr)) < 0)
					{
						ERR_MSG("sendto");
						return -1;
					}
				}
			}
			break;

		}
	
		}
	}

	else if(pid > 0)
	{
		while(1)
		{
		//发送
		strcpy(msg_send.user,"管理员");
		memset(msg_send.text,0,32);
		fgets(msg_send.text,32,stdin);
		msg_send.text[strlen(msg_send.text)-1] = 0;
		msg_send.code = 3;
		if(sendto(sfd,&msg_send,sizeof(msg_send),0,(struct sockaddr*)&sin,serveraddr_len) < 0)
		{
			ERR_MSG("sendto");
			return -1;
		}

		}
	}
	else
	{
		perror("fork");
		return -1;
	}
	
	kill(pid,SIGKILL);
	wait(NULL);
	//关闭套接字
	close(sfd);

	return 0;
}

客户端client.c

#include"myhead.h"

//创建节点函数
int create_node(node **phead)
{
	*phead = (node *)malloc(sizeof(node));
	if(*phead == NULL)
	{
		printf("内存分配失败\n");
		return -1;
	}
	(*phead)->next = NULL;
	return 0;
}

//尾插
int insert_tail(node *phead,struct sockaddr_in addr)
{
	if(phead == NULL)
	{
		printf("尾插错误\n");
		return -1;
	}
	node *pnew = NULL;
	create_node(&pnew);
	pnew->addr = addr;
	node *ptmp = phead;
	while(ptmp->next != NULL)
	{
		ptmp = ptmp->next;
	}
	ptmp->next = pnew;
	return 0;
}


int main(int argc, const char *argv[])
{
	if(argc < 3)
	{
		printf("请输入IP或者端口号\n");
		return -1;
	}

	//创建套接字
	int sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	//填充服务器信息结构体
	struct sockaddr_in sin;
	memset(&sin,0,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 sin_len = sizeof(sin);

	int bytes = 0;
	char name[32] = {0};
	msg_t msg;

	struct sockaddr_in cin;
	memset(&cin,0,sizeof(cin));
	socklen_t cin_len = sizeof(cin);

	//登录操作
	printf("请输入登录信息:");
	msg.code = 1;
	memset(msg.user,0,32);
	fgets(name,32,stdin);
	strcpy(msg.user,name);
	msg.user[strlen(msg.user)-1] = 0;
	if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len) < 0)
	{
		ERR_MSG("sendto");
		return -1;
	}

	//创建进程
	pid_t pid = fork();

	if(pid == 0)
	{
		while(1)
		{
			memset(&msg,0,sizeof(msg));
			//接收服务器应答
			if((bytes=recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,&sin_len)) < 0)
			{
				ERR_MSG("recvfrom");
				return -1;
			}
			if(strcmp(msg.user,name) == -10)
			{
				continue;
			}else{
				switch(msg.code)
				{
				case 1:
					printf("[%s]上线了\n",msg.user);
					break;
				case 2:
					printf("[%s]:%s\n",msg.user,msg.text);
					break;
				case 3:
					printf("[%s]退出了\n",msg.user);
					break;
				}
			}
		}
	}
	else if(pid > 0)
	{
		while(1)
		{
			//在终端获取群聊
			memset(msg.text,0,128);
			fgets(msg.text,128,stdin);
			msg.text[strlen(msg.text)-1] = 0;
			if(strcmp(msg.text,"quit") == 0)
			{
				msg.code = 3;
				if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len) < 0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				break;
			}
			else{
				msg.code = 2;
			}
			if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len) < 0)
			{
				ERR_MSG("sendto");
				return -1;
			}
		}
	}
	
	close(sfd);

	return 0;
}

执行结果:

 


网站公告

今日签到

点亮在社区的每一天
去签到