网络编程作业4

基于UDP的网络聊天室:

网络编程作业4_第1张图片

服务器代码:

#include

struct cin_fm
{
	char type;
	char name[20];
	char text[128];
};

int main(int argc, const char *argv[])
{
	//判断输入是否正确
	if(argc!=3){
		printf("enter error\n");
		return -1;
	}

	//创建用于通信的套接字
	int sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sfd == -1)
	{
		perror("socket error");
		return -1;
	}

	//bind绑定端口号和ip地址
	struct sockaddr_in sin;
	sin.sin_family 	= AF_INET;                   //ipv4通信
	sin.sin_port 	= htons((short)(atoi(argv[2])));            //端口号
	sin.sin_addr.s_addr = inet_addr(argv[1]);      //ip地址

	if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) ==-1)
	{
		perror("bind error");
		return -1;
	}

	printf("bind success\n");

	//定义客户端结构体数组
	struct sockaddr_in cin[100];
	for(int i=0;i<100;i++)
		cin[i].sin_family = AF_INET;

	//定义一个集合管理文件描述符
	struct pollfd fds[100];
	int i;
	//清空集合
	for(i=0;i<100;i++){
		fds[i].fd=-1;
	}

	//将标准输入描述符放入集合中
	fds[0].fd=0;
	fds[0].events=POLLIN;
	//将sfd放入集合中
	fds[1].fd=sfd;
	fds[1].events=POLLIN;

	//定义储存客户信息的结构体数组
	struct cin_fm add_cin[100];
	//定义用来通信的结构体和客户信息结构体
	struct cin_fm temp;
	struct sockaddr_in cintemp;
	cintemp.sin_family = AF_INET;
	socklen_t socklen = sizeof(cintemp);

	//清空结构体数组
	for(int i=0;i<100;i++){
		bzero(add_cin[i].name, sizeof(add_cin[0].name));
		bzero(add_cin[i].text, sizeof(add_cin[0].text));
	}

	int res;
	char buf[128] = "";
	int maxcin=0;
	while(1)
	{
		res = poll(fds,2, -1);          //第三个参数如果是负数,表明一直等待
		if(res == -1)
		{
			perror("poll error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		if(fds[1].revents==POLLIN){
			//清空内容
			temp.type=0;
			bzero(temp.name,sizeof(temp.name));
			bzero(temp.text,sizeof(temp.text));

			//读取信息
			recvfrom(sfd,&temp, sizeof(temp), 0, (struct sockaddr*)&cintemp, &socklen);
			//判断是登录,群聊,还是退出
			if(temp.type=='L'){
				printf("%s[%s:%d]:登录成功\n",temp.name,inet_ntoa(cintemp.sin_addr),ntohs(cintemp.sin_port));
				strcpy(add_cin[maxcin].name,temp.name);
				cin[maxcin].sin_port=cintemp.sin_port;
				cin[maxcin].sin_addr.s_addr=cintemp.sin_addr.s_addr;
				maxcin++;
				for(int i=0;i<=maxcin;i++){
					//向所用其他客户端发送数据
					if(cintemp.sin_port==cin[i].sin_port)continue;
					sendto(sfd,&temp, sizeof(temp),0, (struct sockaddr*)&cin[i], sizeof(cin[i]));
				}
			}

			if(temp.type=='C'){
				for(int i=0;i<=maxcin;i++){
					//向所用其他客户端发送数据
					if(cintemp.sin_port==cin[i].sin_port)continue;
					sendto(sfd,&temp, sizeof(temp),0, (struct sockaddr*)&cin[i], sizeof(cin[i]));
				}
				printf("%s[%s:%d]:chat成功\n",temp.name,inet_ntoa(cintemp.sin_addr),ntohs(cintemp.sin_port));
			}

			if(temp.type=='Q'){
				printf("%s[%s:%d]:已离线\n",temp.name,inet_ntoa(cintemp.sin_addr),ntohs(cintemp.sin_port));
				for(int i=0;i<=maxcin;i++){
					//删除该用户
					if(cintemp.sin_port==cin[i].sin_port){
						int t=i;
						for(int j=maxcin;j>=i;j--){
							cin[t]=cin[t+1];
							add_cin[t]=add_cin[t+1];
							t++;
						}
						maxcin--;
					}
					//向所用其他客户端发送数据
					sendto(sfd,&temp, sizeof(temp),0, (struct sockaddr*)&cin[i], sizeof(cin[i]));
				}
			}

		}

		if(fds[0].revents==POLLIN){
			bzero(buf,sizeof(buf));
			//从终端输入中获取数据
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]='\0';
			if(strcmp(buf,"quit")==0){
				close(sfd);
				return 0;
			}
			temp.type='C';
			strcpy(temp.text,buf);
			strcpy(temp.name,"^^^systeam^^^");
			for(int i=0;i<=maxcin;i++){
				//向所用客户端发送数据
				sendto(sfd,&temp, sizeof(temp),0, (struct sockaddr*)&cin[i], sizeof(cin[i]));
			}
		}
	}


	//关闭套接字
	close(sfd);
	return 0;
}

客户端代码:

#include

struct add_cin
{
	char type;
	char name[20];
	char text[128];
};

int main(int argc, const char *argv[])
{
	//1、创建用于通信的套接字
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}

	//填充服务器地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port 	= htons((short)(atoi(argv[2])));        //端口号
	sin.sin_addr.s_addr = inet_addr(argv[1]);      //ip地址


	char buf[128] = "";
	char rbuf[128] = "";
	char nm[20]="";

	//定义客户端信息结构体
	struct add_cin temp;
	bzero(temp.name,sizeof(temp.name));
	bzero(temp.text,sizeof(temp.text));
	//清空内容
	bzero(buf,  sizeof(buf));
	bzero(rbuf,  sizeof(rbuf));
	bzero(nm,sizeof(nm));

	//登录请求
	printf("请输入姓名>>>");
	scanf("%s",nm); //从终端获取数据
	getchar();
	strcpy(temp.name,nm);
	temp.type='L';
	//将数据发送给服务器
	sendto(cfd,&temp, sizeof(temp),0,(struct sockaddr*)&sin, sizeof(sin));
	//定义一个集合管理文件描述符
	struct pollfd fds[2];

	//将标准输入描述符放入集合中
	fds[0].fd=0;
	fds[0].events=POLLIN;
	//将sfd放入集合中
	fds[1].fd=cfd;
	fds[1].events=POLLIN;

	int res;
	while(1)
	{
		res = poll(fds,2, -1);          //第三个参数如果是负数,表明一直等待
		if(res == -1)
		{
			perror("poll error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}
		if(fds[0].revents==POLLIN){
			bzero(buf,sizeof(buf));
			fgets(buf, sizeof(buf), stdin);      //从终端获取数据
			buf[strlen(buf)-1] = '\0';
			if(strcmp(buf,"quit")==0){
				temp.type='Q';
				sendto(cfd,&temp, sizeof(temp), 0, (struct sockaddr*)&sin, sizeof(sin));
				close(cfd);
				return 0;
			}else{
				strcpy(temp.text,buf);
				temp.type='C';
				sendto(cfd,&temp, sizeof(temp), 0, (struct sockaddr*)&sin, sizeof(sin));
			}

		}

		if(fds[1].revents==POLLIN){
			temp.type='N';
			bzero(buf,sizeof(buf));
			bzero(rbuf,sizeof(rbuf));
			//接收服务器段发来的消息
			recvfrom(cfd,&temp,sizeof(temp), 0,NULL,NULL);
			if(temp.type=='L'){
				printf("----%s登录成功----\n",temp.name);
			}
			if(temp.type=='Q'){
				printf("%s已离线\n",temp.name);
			}
			if(temp.type=='C'){
				strcpy(buf,temp.text);
				strcpy(rbuf,temp.name);
				printf("%s:%s\n",rbuf,buf);
				if(strcmp(temp.name,"^^^steam^^^")){
					strcpy(temp.name,nm);
				}
			}

		}
	}
	//关闭套接字
	close(cfd);

	return 0;
}

运行结果:

网络编程作业4_第2张图片

你可能感兴趣的:(网络,php,开发语言)