基于UDP的网络聊天室

发布于:2024-12-18 ⋅ 阅读:(62) ⋅ 点赞:(0)

项目需求:

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

 服务器端

#include <myhead.h>
#define PORT 11111
#define IP "192.168.60.75"
//客户端结构体
typedef struct
{
	struct sockaddr_in addr;
	char name[20];//客户端姓名
	int active;//标志位,确定客户端状态,0下线,1在线
}client;
client clients[50];

//服务器线程处理服务器广播
void *fun(void *oldfd)
{
	int fd = *(int *)oldfd;
	char buff[1024];
	while(1)
	{
		char msg[1024];
		bzero(buff,sizeof(buff));
		fgets(buff,sizeof(buff),stdin);
		msg[strlen(msg)-1]='\0';
		sprintf(msg,"服务器消息:%s",buff);
		for(int i=0;i<50;i++)
		{
			if(clients[i].active)
			{
				sendto(fd,msg,sizeof(msg),0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
			}
		}
	}
}
int main(int argc, const char *argv[])
{
	//创建udp套接字
	int oldfd = socket(AF_INET,SOCK_DGRAM,0);
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}

	//绑定套接字
	struct sockaddr_in server = {
	.sin_family = AF_INET,
	.sin_port = htons(PORT),
	.sin_addr.s_addr = inet_addr(IP),             
	};
	if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
	{
		perror("bind");
		return -1;
	}
	printf("聊天室服务器启动,监听端口:%d\n",PORT);

	struct sockaddr_in client;
	socklen_t client_len = sizeof(client);
	int client_count=0;
	char buff[1024];

	//服务器广播发送消息线程
	pthread_t tid;
	tid = pthread_create(&tid,NULL,fun,&oldfd);
	if(tid==-1)
	{
		perror("pthread_create");
		return -1;
	}

	while(1)
	{
		memset(buff,0,sizeof(buff));
	
		//接收消息
		int len = recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&client,&client_len);
		//添加新客户端
		if(len>0)
		{
			if(buff[0]=='L')
			{
				//检查客户端是否已经存在
				int found=0;
				for(int i=0;i<client_count;i++)
				{
					if(clients[i].addr.sin_addr.s_addr == client.sin_addr.s_addr &&
						clients[1].addr.sin_port == client.sin_port)
					{
						found = 1;
						printf("该用户已登录\n");
						break;
					}
				}
				//确保是新用户且服务器数量没有超过最大预设值
				if(!found && client_count < 50)
				{
					//将active空置的客户端结构体存放新客户端信息
					for(int i=0;i<=client_count;i++)
					{
						if(clients[i].active==0)
						{
							clients[i].addr = client;
							strncpy(clients[i].name,buff+1,19);
							clients[i].active = 1;
							break;
						}
					}
					//广播用户登录消息
					char login[1024];
					sprintf(login,"系统消息:%s加入聊天室",clients[client_count].name);

					for(int i=0;i<client_count;i++)
					{
						if(clients[i].active)
						{
							sendto(oldfd,login,sizeof(login),0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
						}
					}
					client_count++;
				}
			}
			else if(buff[0]=='M')
			{
				//转发消息给其他用户
				printf("%s\n",buff+1);//客户端输出消息
				for(int i=0;i<client_count;i++)
				{
					//转发给在线的用户,且不转发给发送消息的客户端
					if(clients[i].active && (clients[i].addr.sin_addr.s_addr != client.sin_addr.s_addr ||
                         clients[i].addr.sin_port != client.sin_port))
					{
						sendto(oldfd,buff+1,sizeof(buff)-1,0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
					}
				}
			}
			else if(buff[0]=='Q')
			{
				//客户端广播退出消息
				for(int i=0;i<client_count;i++)
				{
					if(clients[i].addr.sin_addr.s_addr == client.sin_addr.s_addr &&
						clients[i].addr.sin_port == client.sin_port)
					{
						clients[i].active = 0;

						char quit[1024];
						sprintf(quit,"系统消息:%s离开了聊天室",clients[i].name);

						for(int j=0;j<client_count;j++)
						{
							if(clients[j].active)
							{
								sendto(oldfd,quit,sizeof(quit),0,(struct sockaddr *)&clients[j].addr,sizeof(clients[j].addr));
							}
						}
						break;
					}
				}
			}
		}
	}
	return 0;
}

客户端

#include <myhead.h>
#define IP  "192.168.60.75"
#define PORT 11111

void *message(void *oldfd)
{
	int fd = *(int *)oldfd;
	char buff[1024];

	while(1)
	{
		bzero(buff,sizeof(buff));
		if(recvfrom(fd,buff,sizeof(buff),0,NULL,NULL)>0)
		{
			printf("%s\n",buff);
		}
	}
	exit(0);
}
int main(int argc, const char *argv[])
{
	//创建套接字
	int oldfd = socket(AF_INET,SOCK_DGRAM,0);
	if(oldfd==-1)
	{
		perror("socket");
		return -1;
	}
	
	struct sockaddr_in server = {
	.sin_family = AF_INET,
	.sin_port = htons(PORT),
	.sin_addr.s_addr = inet_addr(IP),
	};

	//输入用户名
	char name[20];
	printf("请输入用户名:");
	fgets(name,sizeof(name),stdin);
	name[strlen(name)-1]='\0';

	//发送登录消息
	char buff[1024];
	buff[0]='L';
	strcpy(buff+1,name);
	sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&server,sizeof(server));
	
	//创建接收消息的线程
	pthread_t  tid;
	tid = pthread_create(&tid,NULL,message,&oldfd);
	if(tid==-1)
	{
		perror("pthread_create");
		return -1;
	}

	//循环处理发送消息
	while(1)
	{
		char msg[1024];
		bzero(msg,sizeof(msg));
		fgets(msg+1,sizeof(msg)-1,stdin);
		//msg[strlen(msg)-1]='\0';

		//退出客户端
		if(strcmp(msg+1,"quit\n")==0)
		{
			printf("1\n");
			msg[0]='Q';
			msg[strlen(msg)-1] = '\0';
			sendto(oldfd,msg,sizeof(msg),0,(struct sockaddr *)&server,sizeof(server));
			break;
		}
		else
		{
			//发送消息
			msg[0]='M';
			char infor[1024];
			sprintf(infor,"%s:%s",name,msg+1);
			strcpy(msg+1,infor);
			sendto(oldfd,msg,sizeof(msg),0,(struct sockaddr *)&server,sizeof(server));
		}
	}
	close(oldfd);
	return 0;
}

运行效果


网站公告

今日签到

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