18--SELECT-TCP-服务器编程模式(2)

1. select函数

         int select(int nfds,   /// 测试文件描述符集合中,范围是0~(nfds-1)

                           fd_set *readfds,

                          /// 读文件描述符号集合

                          /// 该参数即是输入,也是输出

                         /// 输入: 被监视的描述符号

                         输出: 有数据的描述符号

                           fd_set *writefds,

                            fd_set *exceptfds,

                            struct timeval *timeout);// 指定阻塞时间限制,若为NULL,永久

                返回:

                          >0: 发生改变的文件描述符号个数

                        =0: 时间限制过期

                        =-1: 异常

  2. IO能否发出信号?

           一步io通过信号工作。

  案例:

     使用select 实现TCP的多客户连接于处理


// chatServer.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>

main()
{
	int sfd; // 服务器描述符
	int fdall[100]; // 客户描述符号
	int count; // 客户个数
	int r; // 返回值(异常处理)
	struct sockaddr_in dr; // IP地址与端口
	fd_set fds; // 被select监控的描述符号集合
	int maxfd; // 最大文件描述符号
	int i,j;   // 循环变量
	char buf[1024]; // 客户聊天程序缓冲
	
// 1. 建立socket
	sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd == -1) printf("socket err:%m\n"),exit(-1);
	printf("socket OK!\n");
// 2. 绑定地址与端口
	dr.sin_family = AF_INET;
	dr.sin_port = htons(6666);
	inet_aton("120.6.111.13",&dr.sin_addr);
	r = bind(sfd,(struct sockaddr*)&dr,sizeof(dr));
	if(r== -1) printf("bind err:%m\n"),close(sfd),exit(-1);
	printf("bind ok!\n");
// 3.监听
	r = listen(sfd,10);
	if(r==-1) printf("listen err:%m\n"),close(sfd),exit(-1);
	printf("listen OK!\n");
// 初始化
	count = 0;
	maxfd = 0;
	FD_ZERO(&fds);
	for(i=0;i<100;++i)
	{
		fdall[i] = -1;// 客户的最大数为100,初始化为-1
	}
	while(1)
	{
		// 4. 构建监听的描述符号集合
		// 4.1 清空
		FD_ZERO(&fds);
		maxfd = 0;
		// 4.2 加入服务器描述符号
		FD_SET(sfd,&fds);
		maxfd = maxfd >= sfd ? maxfd:sfd;
		// 4.3 加入客户描述符号
		for(i=0; i<count;++i)
		{
			if(fdall[i] != -1)
			{
				FD_SET(fdall[i],&fds);
				maxfd = maxfd >= fdall[i]?maxfd:fdall[i];
			}
		}
		//5. 使用select循环控制描述符号
		r = select(maxfd+1,&fds,0,0,0);
		if( r==-1)
		{
			printf("服务器崩溃!\n");
			break;
		}
		//6. 分两种清空处理:
		// 6.1 有客户连接:服务器描述符号
		if(FD_ISSET(sfd,&fds))
		{
			fdall[count] = accept(sfd,0,0);
			if(fdall[count] == -1)
			{
				printf("服务器崩溃!\n");
				break;
			}
			printf("有客户连接!\n");
			count++;
		}
		// 6.2 有客户发送数据:客户描述符号
		for(i=0;i<count;++i)
		{
			// 判定改变描述符号适合存在
			if(fdall[i] != -1 && FD_ISSET(fdall[i],&fds))
			{
				// 读取数据
				r = recv(fdall[i],buf,1023,0);
				if(r==0)
				{
					printf("有客户退出!\n");
					close(fdall[i]);
					fdall[i] = -1;
				}
				if(r== -1)
				{
					printf("网络故障!\n");
					close(fdall[i]);
					fdall[i] = -1;
				}
				if(r>0)
				{
					// 广播数据
					buf[r] = 0;
					printf("广播数据:%s\n",buf);
					for(j=0;j<count;++j)
					{
						if(fdall[j] != -1)
						{
							send(fdall[j],buf,r,0);
						}
					}
				}
			}
		}
	}

}

客户端使用第17个笔记的客户端

显示效果






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值