华清远见嵌入式学习——网络编程——小项目

项目要求:

华清远见嵌入式学习——网络编程——小项目_第1张图片

代码实现:

服务器端:

#include 

//定义协议包
struct proto
{
	char type;
	char name[20];
	char text[128];	
};


int main(int argc, const char *argv[])
{
	//判断从终端输入的字符串的个数
	if(argc != 3)
	{
		printf("input error\n");
		printf("usage:./a.out 本机IP 本机端口\n");
		return -1;
	}

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

	//设置端口号快速重用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
	{
		perror("setsockopt error");
		return -1;
	}

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

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

	//定义客户端地址信息结构体
	struct sockaddr_in cin;
	cin.sin_family = AF_INET;

	socklen_t socklen = sizeof(cin);

	//定义客户端地址信息结构体数组,用于存放多个客户端地址信息
	struct sockaddr_in savecin[1024];

	//初始化每个信息结构体内的第一个成员
	for(int i = 0;i < 1024;i++)
	{
		savecin[i].sin_family = AF_INET;
	}

	定义一个用于检测文件描述符的集合
	fd_set readfds, tempfds;                          //在栈区定义

	清空容器中的内容
	FD_ZERO(&readfds);
	将要检测的文件描述符放入集合中
	FD_SET(sfd, &readfds);           //将sfd文件描述符放入
	FD_SET(0, &readfds);             //将0号文件描述符放入

	//对客户端的数据进行保存和转发

	char buf[256] = "";
	int res1,res2;
	int n = 0;

	//定义协议包结构体变量
	struct proto pro;
	struct proto send;

	while(1)
	{
		bzero(buf,sizeof(buf));

		tempfds = readfds;

		使用select阻塞等待集合中的文件描述符有事件产生
		res1 = select(sfd+1, &tempfds, NULL, NULL, NULL);
		if(res1 == -1)
		{
			perror("select error");
			return -1;
		}else if(res1 == 0)
		{
			printf("time out\n");
			return -1;
		}


		//接收客户端信息
		if(FD_ISSET(sfd,&tempfds))
		{
			res2 = recvfrom(sfd,&pro,sizeof(pro),0,(struct sockaddr *)&cin,&socklen);
			if(res2 == -1)
			{
				perror("recvfrom error");
				return -1;
			}

			//登录时存储客户端到数组中
			if(pro.type == 'L')
			{
				savecin[n] = cin;
				n++;

				sprintf(buf,"---%s已上线---",pro.name);

				printf("%s\n",buf);
				for(int i = 0;i < n;i++)
				{
					if(savecin[i].sin_port == cin.sin_port)
					{
						continue;
					}	
					sendto(sfd,&pro,sizeof(pro),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

				}


			}


			if(pro.type == 'C')
			{
					//群聊
					send.type = pro.type;
					strcpy(send.name,pro.name);
					strcpy(send.text,pro.text);

					for(int i = 0;i < n;i++)
					{
						if(savecin[i].sin_port == cin.sin_port)
						{
							continue;
						}	
						sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

					}

			}
			if(pro.type == 'Q')
			{
				//下线
				send.type = pro.type;
				strcpy(send.name,pro.name);
				strcpy(send.text,pro.text);

				for(int i = 0;i < n;i++)
				{
					bzero(buf,sizeof(buf));

					sprintf(buf,"---%s已下线---\n",send.name);

					printf("%s\n",buf);



					//删除该用户
					if(savecin[i].sin_port == cin.sin_port)
					{
						int t = i;
						for(int j = i;j <= n;j++)
						{
							savecin[t] = savecin[t+1];
							t++;				
						}
					}
					n--;
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

				}
			}
		}
		if(FD_ISSET(0,&tempfds))
		{
			bzero(send.name,sizeof(send.name));
			bzero(send.text,sizeof(send.text));

			send.type = 'C';
			strcpy(send.name,"系统消息");

			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1] = '\0';

			for(int i = 0;i <= n;i++)
			{


				sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));
			}	
		}
	}
	//关闭套接字文件描述符
	close(sfd);
	return 0;
}

客户端:

#include 

//定义协议包结构体
struct proto
{
	char type;
	char name[20];
	char text[128];
};

int main(int argc, const char *argv[])
{
	//判断终端输入的字符串的个数
	if(argc != 3)
	{
		printf("input error\n");
		printf("usage:./a.out 服务器IP 服务器端口号\n");
		return -1;
	}

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

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

	//定义协议包结构体变量
	struct proto pro;


	//填充登录协议

	printf("请输入姓名>>");

	//登录
	pro.type = 'L'; 

	fgets(pro.name,sizeof(pro.name),stdin);
	pro.name[strlen(pro.name)-1] = '\0';

	sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

	定义一个用于检测文件描述符的集合
	fd_set readfds, tempfds;                          //在栈区定义

	清空容器中的内容
	FD_ZERO(&readfds);
	将要检测的文件描述符放入集合中
	FD_SET(cfd, &readfds);           //将sfd文件描述符放入
	FD_SET(0, &readfds);             //将0号文件描述符放入

	//向服务器发送或从服务器接收消息
	char rbuf[128] = "";
	int res = 0;
	char name1[20] = "";
	strcpy(name1,pro.name);


	while(1)
	{

		将集合内容复制一份
		tempfds = readfds;

		使用select阻塞等待集合中的文件描述符有事件产生
		res = select(cfd+1, &tempfds, NULL, NULL, NULL);
		if(res == -1)
		{
			perror("select error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		//群聊和退出
		if(FD_ISSET(0,&tempfds))
		{
			bzero(pro.text,sizeof(pro.text));
			
			//从终端获取内容
			fgets(pro.text,sizeof(pro.text),stdin);
			pro.text[strlen(pro.text)-1] = '\0';

			if(strcmp(pro.text,"quit") == 0)
			{
				//退出
				pro.type = 'Q';
				sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

				//关闭套接字文件描述符
				close(cfd);


				break;
			}else
			{
				//群聊
				pro.type = 'C';
				sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

			}
		}

		//接收来自服务器的消息
		if(FD_ISSET(cfd,&tempfds))
		{

			bzero(rbuf,sizeof(rbuf));
			bzero(pro.text,sizeof(pro.text));

			res = recvfrom(cfd,&pro,sizeof(pro),0,NULL,NULL);
			if(res < 0)
			{
				perror("recvfrom error");
				return -1;
			}

			if(pro.type == 'L')
			{
				printf("---%s已登录---\n",pro.name);
			}
			if(pro.type == 'C')
			{
				printf("%s:%s\n",pro.name,pro.text);
				if(strcmp(pro.name,"系统消息") == 0)
				{
					strcpy(pro.name,name1);
				}
			}
			if(pro.type == 'Q')
			{
				printf("---%s已下线---\n",pro.name);
			}
		}


	}
	//关闭套接字文件描述符
	close(cfd);

	return 0;
}

代码运行效果图:

你可能感兴趣的:(学习)