如何从内核角度看怎么设置connect超时?从这两点入手
我们在编写网络程序时,通常需要连接其他服务端(如微服务之间的通信),这时就需要通过调用 connect 函数来连接服务端。但我们发现 connect 函数并没有提供超时的设置,而在 Linux 系统中,connect 的默认超时时间为75秒。所以,在连接不上服务端的情况下,我们需要等待75秒,这对我们不能接受的。
通过 SO_SNDTIMEO 设置 connect 超时时间
虽然 connect 系统调用没有提供超时的设置,但我们通过查阅 Linux 内核代码可以发现,connect 系统调用的超时时间可以通过 SO_SNDTIMEO 参数来设定的,而 SO_SNDTIMEO 参数可以通过 setsockopt 系统调用来设置,如下代码:
一般来说,SO_SNDTIMEO 参数是用来设置 socket 的发送超时时间,为什么在 Linux 中还能设置 connect 的超时时间呢?我们来查看一下 connect 系统调用的实现:
在 inet_stream_connect 函数中,首先调用了 sock_sndtimeo 获取 socket 的 SO_SNDTIMEO 的值,我们来看看 sock_sndtimeo 函数的实现:
sock_sndtimeo 函数只是简单的从 socket 对象中获取 sndtimeo 字段的值,如果 socket 被设置了非阻塞,那么就返回0。
我们接着分析 inet_stream_connect 函数,在获取到 SO_SNDTIMEO 的值后,就调用 inet_wait_for_connect 函数等待 socket 连接返回。返回三种情况:
连接成功了。
连接超时了。
连接被中断了。
如果连接成功,connect 会返回0;如果连接超时,connect 会返回 EINPROGRESS 错误;如果连接被中断,connect 会返回 EINTR 错误。
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)


通过非阻塞与多路复用IO设置 connect 超时时间
从上面的分析可以看到,当把 socket 设置为非阻塞时,connect 系统调用会立刻返回 EINPROGRESS 错误,这时我们可以把 socket 添加到多路复用 IO 中进行监听,并且设置多路复用 IO 的超时时间即可达到设置 connect 超时时间的目的,如下代码:
connect_timeout 函数实现了有超时机制的 connect,其主要步骤有:
通过调用 fcntl 函数把 socket 设置为非阻塞。
调用 connect 函数进行连接服务端。
如果 connect 函数返回 EINPROGRESS 或者 EWOULDBLOCK 错误,表示连接还没有建立,所以此时把 socket 添加到选择 中进行监听,并且设置选择 的超时时间。
判断选择 的返回值,如果返回值大于0,表示连接成功;如果返回值小于0,表示连接出错;如果反正等于0,表示连接超时。
最后把 socket 恢复到阻塞模式。
这种设置 connect 的超时时间的方式比前面设置 SO_SNDTIMEO 值的方式更为通用,因为在非 Linux 系统中,设置 SO_SNDTIMEO 值的方式不一定有效。
