
若有收获,请记得分享和转发哦
代码执行send成功后,数据就发出去了吗?
回答这个问题之前,需要了解什么是Socket 缓冲区。
Socket 缓冲区
什么是 socket 缓冲区
编程的时候,如果要跟某个IP建立连接,我们需要调用操作系统提供的 socket API
。
socket 在操作系统层面,可以理解为一个文件。
我们可以对这个文件进行一些方法操作。
用listen
方法,可以让程序作为服务器监听其他客户端的连接。
用connect
,可以作为客户端连接服务器。
用send
或write
可以发送数据,recv
或read
可以接收数据。
在建立好连接之后,这个 socket 文件就像是远端机器的 "代理人" 一样。比如,如果我们想给远端服务发点什么东西,那就只需要对这个文件执行写操作就行了。
socket_api
怎么观察 socket 缓冲区
如果想要查看 socket 缓冲区,可以在linux环境下执行 netstat -nt
命令。
答案是不确定!执行 send 之后,数据只是拷贝到了socket 缓冲区。至 什么时候会发数据,发多少数据,全听操作系统安排。
在用户进程中,程序通过操作 socket 会从用户态进入内核态,而 send方法会将数据一路传到传输层。在识别到是 TCP协议后,会调用 tcp_sendmsg 方法。
如果此时 socket 是非阻塞的,程序就会立刻返回一个
EAGAIN
错误信息,意思是Try again
, 现在缓冲区满了,你也别等了,待会再试一次。
我们可以简单看下源码是怎么实现的。还是回到刚才的 tcp_sendmsg
发送方法中。
如果接收缓冲区为空,执行 recv 会怎么样?
如果socket缓冲区还有数据,执行close了,会怎么样?
首先我们要知道,一般正常情况下,发送缓冲区和接收缓冲区 都应该是空的。
如果发送、接收缓冲区长时间非空,说明有数据堆积,这往往是由于一些网络问题或用户应用层问题,导致数据没有正常处理。
那么正常情况下,如果 socket
缓冲区为空,执行 close
。就会触发四次挥手。
这个也是面试老八股文内容了,这里我们只需要关注第一次挥手,发的是 FIN
就够了。
socket
缓冲区是个先进先出的队列,这种情况是指内核会等待TCP层安静把发送缓冲区数据都发完,最后再执行 四次挥手的第一次挥手(FIN包)。
有一点需要注意的是,只有在接收缓冲区为空的前提下,我们才有可能走到 tcp_send_fin()
。而只有在进入了这个方法之后,我们才有可能考虑发送缓冲区是否为空的场景。
UDP部分
UDP也有缓冲区吗
说完TCP了,我们聊聊UDP。这对好基友,同时都是传输层里的重要协议。既然前面提到TCP有发送、接收缓冲区,那UDP有吗?
以前我以为。
"每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。"
后来我发现我错了。
而我们大部分情况下,都不会用 MSG_MORE
,也就是来一个数据包就直接发一个数据包。从这个行为上来说,虽然UDP用上了发送缓冲区,但实际上并没有起到"缓冲"的作用。