简单说说select函数的理解

           之前一直困扰于select函数的用法, 不明白他到底何用,后来自己动手写了C/S框架,

才慢慢对select函数有了一点点的了解,所以今天加班整理出来,方便大家一起学习讨论。

      对于select函数的原型以及参数我就不多说了,可以在终端 man select 就清楚了。

直接用代码解释吧

 

while(1){	
//
      cli_sock = accept(ser_sock, (struct sockaddr *)& clieaddr_in, &socklen);
		
		if( cli_sock < 0 )
		{
			perror("accept");
			return -1;
       //其他读写操作
}

最先我服务端代码就直接这样写了,当客户端连上一个后能正常工作,但是当有第二个客户端连上了,

就出问题了,因为下面的读写操作我也是一个while(1)循环来做接收处理的,这样的话就一直阻塞在

read这个函数了,这个时候才想起来了select函数的妙处所在,所以立马修改了代码:

 

  // do something                
                FD_ZERO(&fd_r);
		FD_ZERO(&fd_w);
		FD_SET(ser_sock, &fd_r);
		FD_SET(ser_sock, &fd_w);
		tvv.tv_sec = 2;
		tvv.tv_usec = 0;	
              while(1)
	     {
		//用select()函数进行accept是否有客户端连接到来的轮询,否则程序会可能一直在这里阻塞,
		//当没有客户端到来的时候,用户层不能进行处理
		Ret = select(ser_sock + 1, &fd_r, &fd_w, NULL, &tvv);
		printf("\n [%s]-[%d]: Ret = %d \n", __func__, __LINE__, Ret);
		switch( Ret )
		{
			case -1:
			case 0:
				continue;
			default:
				break;

		}
		
		cli_sock = accept(ser_sock, (struct sockaddr *)& clieaddr_in, &socklen);
		
		if( cli_sock < 0 )
		{
			perror("accept");
			return -1;
		}

                          while(1)

 

                              {

                                       // do something

                             }
 

                     }

重新修改了服务端代码之后,在用客户端去连的时候, 一个问题又出来了,

select函数会立马返回,而且一直在打印select的返回值为0 也就是没有准

备好的写或者读的套接字,我当时也比较郁闷了,明显有套接字连上去的啊,

为什么会没有准备好的呢?此时想到了阻塞时间的那个参数,我就改成了10秒,

结果就可以的,但是如果客户端过了10秒之后再去连接的时候,又出现了相同的

问题了,百思不得其解,回头在去看man手册,才恍然大悟过来:

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do  this.   (POSIX.1-2001  permits  either  behavior.)
This causes problems both when Linux code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for
multiple select()s in a loop without reinitializing it.  Consider timeout to be undefined after select() returns.

对于英文我不敢妄动的去说的真正意思,但是我只能片面的说说我的理解:

select函数会修改timeout的值还反应还没有睡眠的时间,(就这一句话就足一解决了上面的问题了,也到了select的门道)。

后面的意思我就不多解释,主要就是代码移植可能照成的阻塞时间的修改之类的。

原来每次返回select都会修改阻塞的时间,所以你在while外面给select赋值阻塞时间值的话,每次循环都会消耗掉相关阻塞时间的,

最后在阻塞时间为0时,就一直在continue,客户端也就无法连接进来了,同时,相关fd_set这些 读写,异常的 检查套接字也是会改变的,

所以每次循环都是必须重新作赋值操作才是有效的,不然会出现无法预料的意外

知道上面的错误后们重新修改代码后:

 

	int Ret = -1;
	fd_set fd_r,fd_w;

	struct timeval tvv;
	
	while(1)
	{
		//用select()函数进行accept是否有客户端连接到来的轮询,否则程序会可能一直在这里阻塞,
		//当没有客户端到来的时候,用户层不能进行处理
		FD_ZERO(&fd_r);
		FD_ZERO(&fd_w);
		FD_SET(ser_sock, &fd_r);
		FD_SET(ser_sock, &fd_w);
		tvv.tv_sec = 2;
		tvv.tv_usec = 0;

		Ret = select(ser_sock + 1, &fd_r, &fd_w, NULL, &tvv);
		
		printf("\n [%s]-[%d]: Ret = %d \n", __func__, __LINE__, Ret);
		switch( Ret )
		{
			case -1:
			case 0:
				continue;
			default:
				break;

		}
		
		cli_sock = accept(ser_sock, (struct sockaddr *)& clieaddr_in, &socklen);
		
		if( cli_sock < 0 )
		{
			perror("accept");
			return -1;
		}
           //do something

         }

 

这样之后,果然,问题基本解决了或许还是我懂的太少!

开始搞网络编程也就半年时间左右,APUE还没看完,偶尔用时才翻一翻

以上就是我对select函数的理解,可能只是冰山一角,但是也拿出来大家分享一下,

有什么说的不周到的地方,大家可以指点一二,大家相互学习,相互进步!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

max_min_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值