网络编程作业7

本文详细介绍了使用UDP协议实现的网络聊天室服务器和客户端的代码,涉及套接字创建、端口复用、绑定、数据收发以及用户认证和消息传递功能。
摘要由CSDN通过智能技术生成

基于UDP的网络聊天室

服务器代码:

#include "head.h"

int main(int argc, const char *argv[])
{//创建套接字
	int sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd == -1)
	{
		perror("socket error");
		return -1;
	}
	printf("套接字创建成功!  sfd = %d\n",sfd);
	//端口号快速重用
	int reuse = -1 ;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
	{
		perror("setsockopt error");
		return -1;
	}
	printf("端口快速重用成功!\n");
	//绑定
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SER_PORT);
	sin.sin_addr.s_addr = inet_addr(SER_IP);
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
	{
		perror("bind error");
		return -1;
	}
	printf("绑定成功!\n");
	//数据收发
	struct sockaddr_in cin;
	socklen_t socklen = sizeof(cin);

	//创建一个用于检测文件描述符的容器
	struct pollfd pfds[2];
	pfds[0].fd = sfd;          //表示第一个元素检测0号文件描述符
	pfds[0].events = POLLIN;   //要检测0号文件描述符的读事件
	pfds[1].fd = 0;          //表示第一个元素检测0号文件描述符
	pfds[1].events = POLLIN;   //要检测0号文件描述符的读事件
	int res=-1;
	struct usr usr_arr[1024]={0};
	struct cli_msg cli;
    char wbuf[128]="";
	char buf[128]="";
	int i=0;
	while(1)
	{

		res = poll(pfds,2,-1);         //阻塞检测文件描述符集合中是否有事件产生
		if(res == 0)
		{
			printf("time out\n");
			return -1;
		}else if(res == -1)
		{
			perror("poll error");
			return -1;
		}

jixu:
		//读事件
		if(pfds[0].revents == POLLIN)
		{
			recvfrom(sfd,(struct cli_msg*)&cli,sizeof(cli),0,(struct sockaddr*)&cin,&socklen);


			//判断消息类型
			if(cli.type == 1)
			{
				int k=0;
				int a=1;
				//遍历数组将消息判断用户名是否重复并发回判断结果
				while(k<i)
				{   
					if(strcmp(usr_arr[k].usrname,cli.usrname)==0)
					{
						strcpy(buf,"1");
						sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin));
						goto jixu;
					}else
					{
						k++;
					}
				}
				strcpy(buf,"2");
				sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin));

				//客户端ID和地址信息存入
				strcpy(usr_arr[i].usrname,cli.usrname);
				usr_arr[i].cin = cin;
				printf("--------------------%s已上线--------------------\n",usr_arr[i].usrname);
				i+=1;
			}

			else if(cli.type == 2)
			{
				int l = 0;
				int a ;
				printf("%s:%s\n",cli.usrname,cli.msgText);

				if(strcmp(cli.msgText,"quit")==0)
				{
					for(l=0;l<i;l++)
					{
						if(cin.sin_port == usr_arr[l].cin.sin_port)
						{
							printf("--------------------%s已下线--------------------\n",usr_arr[l].usrname);
							for(a=l;a<i;a++)
							{
								usr_arr[a]=usr_arr[a+1];
							}
							i--;
							goto jixu;

						}
					}
				}
				for(int j=0;j<i;j++)
				{
					//遍历数组将消息发给其他客户端
					if(usr_arr[j].cin.sin_port != cin.sin_port)
					{
						sendto(sfd,&cli,sizeof(cli),0,(struct sockaddr*)&(usr_arr[j].cin),sizeof(usr_arr[j].cin));
						perror("sendto");
					}
				}

			}

		}



		//写事件
		if(pfds[1].revents == POLLIN )
		{       
				   memset(cli.msgText,0,sizeof(cli.msgText));
 
				   fgets(cli.msgText,sizeof(cli.msgText),stdin);
				   cli.msgText[strlen(cli.msgText)-1]=0;
				   cli.type = 3;
               for(int c=0;c<i;c++)
			   {
				   sendto(sfd,&cli,sizeof(cli),0,(struct sockaddr*)&(usr_arr[c].cin),sizeof(usr_arr[c].cin));
				   perror("sento");
			   }

		}
	}

	close(sfd);
	return 0;
}

客户端代码:

#include "head1.h"

int main(int argc, const char *argv[])
{//创建套接字
	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}
	//printf("套接字创建成功!  cfd = %d\n",cfd);
	//端口号快速重用
	int reuse = -1 ;
	if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
	{
		perror("setsockopt error");
		return -1;
	}
	//printf("端口快速重用成功!\n");
	//绑定
	/*struct sockaddr_in cin;
	  cin.sin_family = AF_INET;
	  cin.sin_port = htons(CLI_PORT);
	  cin.sin_addr.s_addr = inet_addr(CLI_IP);
	  if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1)
	  {
	  perror("bind error");
	  return -1;
	  }
	  printf("绑定成功!\n");*/
	//数据收发
	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]);


	//创建一个用于检测文件描述符的容器
	struct pollfd pfds[2];
	pfds[0].fd = cfd;          //表示第一个元素检测0号文件描述符
	pfds[0].events = POLLIN;   //要检测0号文件描述符的读事件
	pfds[1].fd = 0;          //表示第一个元素检测0号文件描述符
	pfds[1].events = POLLIN;   //要检测0号文件描述符的读事件
	int res=-1;
	struct usr usr_arr[1024]={0};
	struct cli_msg cli;
	struct cli_msg cli1;
	char buf[128]="";
	int i=0;

	while(1)
	{
		//登陆后输入ID并存入信息结构体中
		printf("\033[01;33;10m请输入ID:\033[0m");
		scanf("%s",cli.usrname);
		//printf("%s\n",cli.usrname);
		cli.type = 1;

		//向服务器发送ID和地址信息
		sendto(cfd,&cli,sizeof(cli),0,(struct sockaddr*)&sin,sizeof(sin));

		//服务器判断ID是否存在后返回结果
		recvfrom(cfd,&buf,sizeof(buf),0,NULL,NULL);

		if(strcmp(buf,"1")==0)
		{
			printf("\033[01;31;10m用户名重复!请重新输入!\033[0m\n");

		}else
		{
			break;
		}
	}

	while(1)
	{

		res = poll(pfds,2,-1);         //阻塞检测文件描述符集合中是否有事件产生
		if(res == 0)
		{
			printf("time out\n");
			return -1;
		}else if(res == -1)
		{
			perror("poll error");
			return -1;
		}

		//读事件
		if(pfds[0].revents == POLLIN)
		{ 
			recvfrom(cfd,&cli1,sizeof(cli1),0,NULL,NULL);
			if(cli1.type ==2)
			{
			printf("\033[01;32;10m%s:\033[0m%s\n",cli1.usrname,cli1.msgText);
			}else if(cli1.type == 3)
			{
				printf("\033[01;31;10m>>>>>>>>>>系统提示:%s<<<<<<<<<<\033[0m\n",cli1.msgText);

			}
		}


		//写事件
		if(pfds[1].revents == POLLIN )
		{
			//memset(cli.msgText,0,sizeof(cli.msgText));
			fgets(cli.msgText,sizeof(cli.msgText),stdin);
			cli.msgText[strlen(cli.msgText)-1]=0;
			cli.type = 2;
			sendto(cfd,(struct cli_msg*)&cli,sizeof(cli),0,(struct sockaddr*)&sin,sizeof(sin));
			//printf("%s\n",cli.msgText);

		}
	}

	close(cfd);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值