图解学习网站:xiaolincoding.com
大家好,我是小林。
最近有个同学跟我反馈,去面腾讯的时候,又被腾讯面试官拷打了 。
因为他是搞 Go 后端的,没怎么接触过 socket 编程,结果问了好几个网络编程的问题,直接懵逼了。
服务端调用listen之后sleep休眠,请问客户端的connect能不能成功?
这个问题实际上在考察大家对于 TCP 三次握手的底层原理,很多同学对于 TCP 三次握手的理解只停留在SYN和ACK报文的交互,而关于三次握手过程中,内核做了哪些事情?socket 编程和三次握手有什么关系?都不太明白,那这样在遇到这种问题就比较难回答了。
我们先看看客户端连接服务端时,发生了什么?
从上面的描述过程,我们可以得知客户端 connect 成功返回是发送完第三次握手后,服务端 accept 成功返回是在三次握手成功之后。
所以,服务端调用listen之后sleep休眠,并不会影响 TCP 三次握手的过程,当服务端调用listen
后,操作系统内核会开始监听指定端口上的连接请求。即使服务端进入sleep
休眠状态,内核仍然会继续监听连接请求,并将其放入到TCP全连接队列中,等待服务端调用 accpet 来获取连接。
我说不影响就不影响吗?
肯定也不一定对的嘛,还是给大家做个实验验证下我的想法对不对。
写了一个简单的服务端代码,服务端调用完 listen 后,直接进入长达 100000 年的休眠(夸张手法)。
然后编译+启动程序!
ok,很顺利,服务端监听了 8080 端口之后就睡觉去了。
接下来,用 linux 的 nc 工具来模仿客户端连接这个端口。
nc 127.0.0.1 8888
来看看结果如何?
结果是正在等待,说明连接是正常建立成功的!
我们可以通过 netstat 命令来确认连接状态。
完全没问题,状态是ESTABLISHED!
说明服务端调用listen之后sleep休眠,客户端的connect是可以成功的,能顺利完成 TCP 三次握手,我前面的理论分析是没问题的。
针对这个问题,还有另外一种问法,服务端没有执行没有 accept,能成功建立 TCP 连接吗?
答案很明显,也是可以的,因为 accept 并不参与三次握手的过程,只是负责从 TCP全连接队列中取出连接。
如果两边建立了连接,然后有一端sleep休眠,请问write和send能不能成功?
我直接结论,是可以成功的。
因为发送方调用 wirte 发送数据的时候,当把数据从应用层拷贝到 socket 发送缓冲区之后,函数就会返回成功了,至于什么时候发数据,发多少数据,这个后续由内核自己做决定。
来源:小白 debug
并不是等接收方调用 read 函数读到数据后,发送方的 write 函数才返回。因此,接收方的进程即使处于睡眠状态,也不会影响发送方执行 wirte。
并且即使发送方进程即使处于睡眠状态,内核依然也是可以正常接收数据,接收到的数据,会被先放到接收缓冲区,等待发送方进程调用 read 从接收缓冲区读取数据。
这两个问题就分析到这里,本质上就是考察大家对 Linux 内核在 TCP 握手和数据传输阶段做了什么事情。
话说回来,感觉腾讯确实很喜欢问网络编程的底层原理啊,以前也分享过好几个同学在面腾讯遇到的网络编程的问题,去图解网站(xiaolincoding.com)翻一翻就可以看到啦。
讲完了,收工,溜了!(是不是像极了下班的样子)
历史好文: