12.24

 client

#include <myhead.h>
//定义信息结构体
struct Msg
{
	char type;
	char name[20];
	char text[128];
};
int main(int argc, const char *argv[])
{
	//终端输入服务端ip地址及端口号
	if(argc!=3)
	{
		printf("输入错误!!!!\n");
		printf("请输入ip地址及端口号\n");
		return -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_addr.s_addr=inet_addr(argv[1]);
	sin.sin_port=htons(atoi(argv[2]));
	socklen_t socklen=sizeof(sin);
	//定义收发消息结构体
	struct Msg send_msg;
	struct Msg recv_msg;

	//先登录
	printf("请输入姓名>>");
	send_msg.type='L';
	char name[20]="";
	fgets(name,sizeof(name),stdin);
	name[strlen(name)-1]=0;
	strcpy(send_msg.name,name);

	//给服务端发上线消息
	sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
	//定义检测文件描述符集合
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);
	FD_SET(cfd,&readfds);
	FD_SET(0,&readfds);
	//接收select返回值
	int res=0;
	while(1)
	{
		tempfds=readfds;
		//检测集合中是否有事件发生
		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(send_msg.text,sizeof(send_msg.text));
			fgets(send_msg.text,sizeof(send_msg.text),stdin);
			send_msg.text[strlen(send_msg.text)-1]=0;
			//quit退出客户端
			if(strcmp(send_msg.text,"quit")==0)
			{
				send_msg.type='Q';
				sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
				close(cfd);
				break;
			}else 
			{
				send_msg.type='C';
				sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
			}
		}
		//触发接收消息
		if(FD_ISSET(cfd,&tempfds))
		{
			bzero(recv_msg.text,sizeof(recv_msg.text));
			res=recvfrom(cfd,&recv_msg,sizeof(recv_msg),0,NULL,NULL);
			if(res<0)
			{
				perror("recvfrom error");
				return -1;
			}
			if(recv_msg.type=='L')
			{
				printf("---%s已上线---\n",recv_msg.name);
			}
			if(recv_msg.type=='Q')
			{
				printf("---%s已下线---\n",recv_msg.name);
			}
			if(recv_msg.type=='C')
			{
				printf("%s:%s\n",recv_msg.name,recv_msg.text);
			}
		}
	}
	close(cfd);
	return 0;
}

 serve

#include <myhead.h>
//信息结构体
struct Msg
{
	char type;
	char name[20];
	char text[128];
};
int main(int argc, const char *argv[])
{
	//判断从终端输入字符串的个数
	if(argc!=3)
	{
		printf("输入错误!!!\n");
		printf("请输入ip地址及端口号\n");
		return -1;
	}
	int sfd=-1;
	if((sfd=socket(AF_INET,SOCK_DGRAM,0))==-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及端口号填充服务器地址信息结构体
	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]);
	//绑定服务器地址信息
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("bind error");
		return -1;
	}
	//创建客户端地址信息结构体用于接收客户端信息
	struct sockaddr_in cin;
	socklen_t socklen=sizeof(cin);
	struct sockaddr_in arr_cin[1024];
	
	//定义检测文件描述符集合
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);
	//接收select返回值
	int res=-1;
	//接收recvfrom返回值
	int count=0;
	int index=0;
	//发送消息容器
	char buf[128]="";
	//定义收发消息结构体
	struct Msg recv_msg;
	struct Msg send_msg;
	while(1)
	{
		tempfds=readfds;
		//检测集合中是否有事件发生
		res=select(sfd+1,&tempfds,NULL,NULL,NULL);
		if(res==0)
		{
			printf("time out\n");
			return -1;
		}else if(res==-1)
		{
			perror("select error");
			return -1;
		}
		//接收到消息
		if(FD_ISSET(sfd,&tempfds))
		{
			count=recvfrom(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&cin,&socklen);
			if(count==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			//收到消息类型为登录型
			if(recv_msg.type=='L')
			{
				//把当前客户端放入客户端数组下标为index的位置
				arr_cin[index]=cin;
				index++;
				//上线格式
				sprintf(buf,"---%s已上线---\n",recv_msg.name);
				printf("%s\n",buf);
				//把上线消息发送给其他客户端
				for(int i=0;i<=index;i++)
				{
					//不发给发信息的客户端
					if(arr_cin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&arr_cin[i],sizeof(arr_cin[i]));
				}
			}
			//收到消息类型为聊天型
			if(recv_msg.type=='C')
			{
				//把接收到的消息发给其他客户端
				send_msg.type=recv_msg.type;
				strcpy(send_msg.name,recv_msg.name);
				strcpy(send_msg.text,recv_msg.text);
				for(int i=0;i<index;i++)
				{
					if(arr_cin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&arr_cin[i],sizeof(arr_cin[i]));
				}

			}
			//收到消息类型为退出型
			if(recv_msg.type=='Q')
			{
				send_msg.type=recv_msg.type;
				strcpy(send_msg.name,recv_msg.name);
				strcpy(send_msg.text,recv_msg.text);
				for(int i=0;i<index;i++)
				{
					bzero(buf,sizeof(buf));
					sprintf(buf,"---%s已下线---\n",send_msg.name);
					printf("%s\n",buf);
					//删除下线客户端
					if(arr_cin[i].sin_port==cin.sin_port)
					{
						for(int j=i;j<=index;j++)
						{
							arr_cin[j]=arr_cin[j+1];
						}
					}
					index--;
					sendto(sfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&arr_cin[i],sizeof(arr_cin[i]));

				}
			}
		}
		//触发终端输入
		if(FD_ISSET(0,&tempfds))
		{
			bzero(send_msg.name,sizeof(send_msg.name));
			bzero(send_msg.text,sizeof(send_msg.text));
			send_msg.type='C';
			strcpy(send_msg.name,"系统消息");
			fgets(send_msg.text,sizeof(send_msg.text),stdin);
			send_msg.text[strlen(send_msg.text)-1]=0;
			for(int i=0;i<=index;i++)
			{
				sendto(sfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&arr_cin[i],sizeof(arr_cin[i]));
			}
		}
	}
close(sfd);
return 0;
}

 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值