一、问题回顾
面试的时候被问到的问题,原问题是:
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
就会正常返回了。