基于TCP的select的聊天室

服务器:

#include<myhead.h>

#define PORT 9999
#define IP "192.168.125.130"

struct Msg
{
	char type;
	char name[20];
	char text[100];
};
struct sock
{
	int fd;
	struct sockaddr_in cin;
};

int main(int argc, const char *argv[])
{
	if(argc != 3)
	{
		printf("输入有误请重新输入\n");
		printf("./a.out IP PORT\n");
		return -1;
	}
	int sfd = -1;
	if((sfd = socket(AF_INET,SOCK_STREAM,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;
    }


	//创建绑定结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	//sin.sin_port = htons(PORT);
	sin.sin_port = htons(atoi(argv[2]));
	//sin.sin_addr.s_addr = inet_addr(IP);
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	//绑定地址信息结构体
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
	{
		perror("bind error");
		return -1;
	}
	printf("bind success\n");
	

	//设置为监听状态
	if(listen(sfd,128) == -1)
	{
		perror("listen error");
		return -1;
	}
	printf("listen success\n");

	struct sockaddr_in cin;
	socklen_t socklen = sizeof(cin);
	
	fd_set readfds;//读文件描述符集合
	//清空集合
	FD_ZERO(&readfds);
	//文件描述符加入集合
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);

	int maxfd = sfd;
	int newfd = -1;
	int res = -1;
	char buf[128] ="";
	fd_set tempfds;
	struct sock arr_cin[1024];//成员信息结构体数组
	struct Msg peo;//接受客户端发来的结构体
	while(1)
	{
		tempfds = readfds;
		//判断产生的事件
		res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(res == -1)
		{
			perror("select error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		//判断事件
		for(int i=0;i<=maxfd;i++)
		{
			if(!FD_ISSET(i,&tempfds))
			{
				continue;
			}
			//发生事件的文件描述符
			if(i == sfd)
			{
				//设置为接收状态
				if((newfd = accept(sfd,(struct sockaddr*)&cin,&socklen)) == -1)
				{
					perror("accept error");
					return -1;
				}
				arr_cin[newfd].cin = cin;
				arr_cin[newfd].fd = newfd;
				printf("[%s:%d] 连接成功, newfd = %d\n", inet_ntoa(arr_cin[newfd].cin.sin_addr),\
						ntohs(arr_cin[newfd].cin.sin_port), newfd); 
				//将新加入的客户端加入数组
				FD_SET(newfd,&readfds);
				if(newfd > maxfd)
				{
					maxfd = newfd;
				}
			}else if(i == 0)
			{
				peo.type = 'c';
				bzero(peo.text,sizeof(peo.text));
				fgets(peo.text,sizeof(peo.text),stdin);
				peo.text[strlen(peo.text)-1]=0;
				strcpy(peo.name,"系统");
				//发送给全部客服端
				for(int index=4;index<=maxfd&&FD_ISSET(index,&readfds);index++)
				{
					send(index,&peo,sizeof(peo),0);
				}
			}else
			{
				//接受客户端发来的消息,并发送给其他人
				bzero(&peo,sizeof(peo));
				res = recv(i,&peo,sizeof(peo),0);


				if(res == 0)
				{
					printf("客户端下线\n");
					close(i);
					FD_CLR(i,&readfds);
					for(int i=maxfd;i>0;i--)
					{
						if(FD_ISSET(i,&readfds))
						{
							maxfd = i;
							break;
						}
					}
					continue;
				}
				


				if(peo.type == 'L')
				{
					sprintf(peo.text,"-----%s上线-------",peo.name);
					for(int index = 4;index<=maxfd&&FD_ISSET(index,&readfds);index++)
					{
						if( i== arr_cin[index].fd )
							continue;
						send(index,&peo,sizeof(peo),0);
					}
				}
				else if(peo.type == 'c')
				{
					for(int index = 4;index<=maxfd&&FD_ISSET(index,&readfds);index++)
					{
						if( i != arr_cin[index].fd )
						{
							printf("%s:%s\n",peo.name,peo.text);//测试
							send(arr_cin[index].fd,&peo,sizeof(peo),0);
						}
					}

				}else if(peo.type == 'Q')
				{
					sprintf(peo.text,"-----%s下线-------",peo.name);
					for(int index = 4;index<=maxfd&&FD_ISSET(index,&readfds);index++)
					{
						if( i== arr_cin[index].fd )
							continue;
						send(index,&peo,sizeof(peo),0);
					}
					close(i);
					FD_CLR(i,&readfds);
					for(int i=maxfd;i>0;i--)
					{
						if(FD_ISSET(i,&readfds))
						{
							maxfd = i;
							break;
						}
					}
					continue;

				}

			}
		}
	}
	close(sfd);

	return 0;
}

客户端:

#include<myhead.h>

#define PORT 9999
#define IP "192.168.125.130"

struct Msg
{
	char type;
	char name[20];
	char text[100];
};

int main(int argc, const char *argv[])
{
	if(argc != 3)
	{
		printf("输入有误请重新输入\n");
		printf("./a.out IP PORT\n");
		return -1;
	}
	int sfd = -1;
	if((sfd = socket(AF_INET,SOCK_STREAM,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;
    }
	//链接
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	//sin.sin_port = htons(PORT);
	//sin.sin_addr.s_addr = inet_addr(IP);
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]);

	if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
	{
		perror("connect error");
		return -1;
	}
	printf("connect success\n");

	//将成员信息发送给服务器
	struct Msg information;

	printf("请输入姓名>>>");
	scanf("%s",information.name);
	getchar();
	information.type = 'L';
	strcpy(information.text, " ");
	printf("-----%s登陆成功-----\n",information.name);
	send(sfd,&information,sizeof(information),0);

	fd_set readfds;
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);
	int maxfd = sfd;

	int res = -1;
	char buf[128] ="";
	fd_set tempfds;
	while(1)
	{
		tempfds = readfds;
		res = select(maxfd+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))
		{
			struct Msg mem;
			mem.type = 'c';//设置类型
			strcpy(mem.name,information.name);//复制名字
			//客户端消息发送个服务器,服务器发送给其他客户端
			bzero(mem.text,sizeof(mem.text));
			fgets(mem.text,sizeof(mem.text),stdin);
			mem.text[strlen(mem.text)-1]=0;
			if(strcmp(mem.text,"quit") == 0)
			{

				mem.type = 'Q';
				send(sfd,&mem,sizeof(mem),0);
				break;
			}

			send(sfd,&mem,sizeof(mem),0);
		}
		else
		{
			struct Msg mem;
			//接收服务器发来的消息
			bzero(&mem,sizeof(mem));
			res = recv(sfd,&mem,sizeof(mem),0);

			if(res == 0)
			{
				printf("客户端下线\n");
				break;
			}else if(res == -1)
			{
				perror("recv");
				return -1;
			}
			if(mem.type == 'L'||mem.type == 'Q')
			{	
				printf("%s\n",mem.text);
			}
			else
				printf("%s:%s\n",mem.name,mem.text);
		}
	}



	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值