免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6981 | 回复: 7
打印 上一主题 下一主题

网络编程select函数第3个参数疑惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-11-10 15:45 |只看该作者 |倒序浏览
网络编程select函数的第三个参数有点不懂,请大家解释以下。
select的第三个参数是   侦听对写事件感兴趣的fd集合。   什么情况下写事件集合中的fd被置?书上说是在内核中的发送缓冲区中有数据时,就表示可写,但还是不明白。
一般对写事件的操作如下
ioctl(fd, FIONBIO, 1);//设置为非阻塞。

FD_SET(fd, &writeset);
ret = select(maxfd+1, &readset, &writeset, NULL, NULL);
if(ret > 0)
{
    if(FD_ISSET(fd, &writeset))
    {
       send(fd, buf, strlen(buf), 0);//之前没有调用过send函数

    }
}

我不解的是,如果在select之没调用send函数,select怎么知道fd的写已被置1,如果fd不置1,FD_ISSET就返回0,那么send函数就没法调用。   我知道这里的buf不是指内核中的发送缓冲区,但还是想不同其中的原由。好像见到的程序都是这么写的。

请大家解释以下。

论坛徽章:
0
2 [报告]
发表于 2007-11-10 16:06 |只看该作者
select返回可写只是说内核缓冲区中的发送缓冲区有空间了,send也只是把数据填充到这个缓冲区中,send成功不代表发送成功或者对端的接收成功,仅仅是把数据发到发送缓冲区上等待着协议栈把这段数据发送出去.

论坛徽章:
0
3 [报告]
发表于 2007-11-10 17:31 |只看该作者
刚才又把select函数的说明看了。稍微明白了一点。
对于可写的fd集合,select检测的是它是否有写的能力,所谓有写的能力就是指缓冲区中有空间放下内容。这样的理解应该对了吧。
谢谢版主的热心。
怎么给分

论坛徽章:
0
4 [报告]
发表于 2007-12-09 14:05 |只看该作者

回复 #1 youngshuai 的帖子

没有发现fd集合清零??下次轮询,能检测出文件描述符变化么???

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
5 [报告]
发表于 2007-12-09 23:52 |只看该作者
也就是一旦文件可写了,select就可以监测到,于是应用程序就可以对这个文件写了。但是具体什么叫可写了?驱动说了算。

论坛徽章:
0
6 [报告]
发表于 2008-02-12 02:25 |只看该作者
我也对这个问题有些不解
那啥时候算是read集合被置位呢?
比如下面的代码
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "restart.h"

int copy2files(int fromfd1, int tofd1, int fromfd2, int tofd2) {
&nbsp;&nbsp;&nbsp;int bytesread;
&nbsp;&nbsp;&nbsp;int maxfd;
&nbsp;&nbsp;&nbsp;int num;
&nbsp;&nbsp;&nbsp;fd_set readset;  
&nbsp;&nbsp;&nbsp;int totalbytes = 0;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxfd = fromfd1;                     /* find the biggest fd for select */
&nbsp;&nbsp;&nbsp;if (fromfd2 > maxfd)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxfd = fromfd2;
&nbsp;
&nbsp;&nbsp;&nbsp;for ( ; ; ) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_ZERO(&readset);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_SET(fromfd1, &readset);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_SET(fromfd2, &readset);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (((num = select(maxfd+1, &readset, NULL, NULL, NULL)) == -1) &&
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(errno == EINTR))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (num == -1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return totalbytes;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (FD_ISSET(fromfd1, &readset)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bytesread = readwrite(fromfd1, tofd1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (bytesread <= 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalbytes += bytesread;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (FD_ISSET(fromfd2, &readset)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bytesread = readwrite(fromfd2, tofd2);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (bytesread <= 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalbytes += bytesread;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;return totalbytes;
}


在第一次select之前,readset中的两个fd(fromfd1和fromfd2)只是两个被open了的fd,也没执行其他操作,那select具体是在什么条件下成功返回呢?
write集合是在内核缓冲区有空闲空间的时候被成功置位返回,那read集合呢?
谢谢!

论坛徽章:
0
7 [报告]
发表于 2008-02-12 14:48 |只看该作者
可读与可写都是驱动的poll函数决定的。

论坛徽章:
0
8 [报告]
发表于 2008-07-04 18:32 |只看该作者
对于可读文件描述符集以下四种情况会导致置位:
1、 socket接收缓冲区中的数据量大于或等于当前缓冲区的低水位线.此时对于read操作不会被阻塞并且返回一个正值(读取的字节数).低水位线可以通过SO_RCVLOWAT选项设定,对于Tcp和Udp来说其默认值为1.
2、socket连接的读端被关闭,如shutdown(socket, SHUT_RD)或者close(socket).对应底层此时会接到一个FIN包,read不会被阻塞但会返回0.代表读到socket末端.
3、socket是一个监听socket并且有新连接等待.此时accept操作不会被阻塞.
4、发生socket错误.此时read操作会返回SOCKET_ERROR(-1).可以通过errno来获取具体错误信息.

对于可写文件描述符集以下四种情况会导致置位:
1、socket发送缓冲区中的可用缓冲大小大于或等于发送缓冲区中的低水位线并且满足以下条件之一
    (1)、socket已连接
    (2)、socket本身不要求连接,典型如Udp
   
    低水位线可以通过SO_SNDLOWAT选项设置.对于Tcp和Udp来说一般为2048.
2、socket连接的写端被关闭,如shutdown(socket, SHUT_WR)或者close(socket).在一个已经被关闭写端的句柄上写数据会得到SIGPIPE的信号(errno).
3、一个非阻塞的connect操作连接成功 或者 connect操作失败.
4、发生socket错误.此时write操作会返回SOCKET_ERROR(-1).可以通过errno来获取具体错误信息.

对于异常文件描述符集只有一种情况(针对带外数据):
当收到带外数据(out-of-band)时或者socket的带外数据标志未被清除.


参考资料: UNP select function
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP