之前的时候谈accept生成新socket时,这个新socket会继承大多数listening socket的属性,但是文件状态标志比如O_NONBLOCK不会被继承。
当时用的settimeout 和 gettimeout来进行验证的。
这是不对的。
因为说settimeout(0) 和 setblocking(0) 是一样的,主要是因为
|
|
看到了吗 settimeout 会在设置 timeout属性时,调用internal_setblocking ,这个也就是setblocking底层实现。
但是通过gettimeout 这个是获取的sock_timeout 属性的值,并不能代表此时的是否设置了O_NONBLOCK。
看下PySocketSockObject 这个数据结构
源码
|
|
这个sock_time 是Python的socket 属性,而非内核socket的属性。
所以在accept 生成新socket时,并不会给这个非内核的socket 继承 listening socket 的属性。
也就是 gettimeout获取的值跟文件状态标志位没有任何关系。
那到底能不能直接看到O_NONBLOCK状态的方法呢。有的fcntl
库。fcntl 可以访问或者修改这些状态标志位(file status flags)。
|
|
获取当前flags 标志位,设置O_NONBLOCK标志。这其实等价于setblocking(0) 可以看下 setblocking 源码
|
|
socket的setblocking是通过fcntl实现的,这也是唯一跟告知内核的方式。
OK,那我们再用fcntl的方式来验证下之前accept继承是否正确。
|
|
输出
|
|
奇怪的事情发生了, accept继承了 listening socket 的文件状态标志位(file status flags)。这是咋回事?
之前说的这个结论不会继承是Linux 内核下说的(我本人的开发机是Mac),Mac OS的内核实现可能不同。
又找了一台Ubuntu机器上试了试
|
|
跟预期一致了,果然没有继承。
看来不同的操作系统内核的实现有略微的不同,因此不要依赖于accept时的继承,把accept生成的socket也进行显式的修改。不论你是用setsockopt还是fcntl, 最好在accept生成的socket再显式来设置一次。
推荐一个在线看Python源码的网站