connect & send 在三次握手过程中的有趣问题
一、问题回顾
面试的时候被问到的问题,原问题是:
1:写一下socket网络编程服务端和客户端常用的函数。
2:如果服务端在listen之后没有accept,那客户端的connect会返回吗?为什么?
3:此时调用send发数据会怎么样?
在看下面答案之前,推荐阅读:
深入探索 Linux listen() 函数 backlog 的含义
Socket accept queue is full 但是一个连接需要从SYN->ACCEPT
下面是我对这个问题实验整理的结果:
| 情况 | ESTABLISHED 队列没有满 | SYN_RECV队列没有满 | SYN_RECV 队列满了 |
|---|---|---|---|
| connect返回情况 | connect 正常返回 | connect 正常返回 | connect返回timeout错误 |
| send写数据 | 完全正常写,并且数据会被服务器回复ack确认。之后如果accept,可以read出数据。 | 不能正常发送,会不断触发重传,但是数据不会被确认。 | 这时候的socket是完全disconnect的,send给disconnect的socket写数据,触发SIGPIPE信号,默认杀死本进程。 |
二、总结
有关connect函数返回错误的情况,常见的有下面三种:
- 返回
TIMEOUT,即SYN_RECV队列都满了,对于客户端发来的三次握手第一次的SYN都没有办法响应,这时候TCP会隔6s,24s重发,直到75s,如果还是没有被接受,最后返回TIMEOUT错误。 - 返回
ECONNREFUSED错误,表示服务器主机没有在相应的端口开启监听。 - 返回
EHOSTUNREACH或ENETUNREACH,表示在某个中间路由节点返回了ICMP错误,这个错误被内核先保存,之后继续按照6s,24s重发,直到75s,如果还是没有响应,就返回EHOSTUNREACH或ENETUNREACH错误。
我那个问题只涉及了TIMEOUT的情况,没有后两种,另外:
connect什么时候正常返回?其实是客户端收到服务器三次握手第二次返回的
SYN+ACK之后,自己进入了ESTABLISHED状态(TCP状态转换图),这时候connect就会正常返回了。
浙公网安备 33010602011771号