当前位置:首页 > 单片机 > 小林coding
[导读]今天又是被倾盆的需求淹没的一天。有没有人知道,那种“我用3句话,就让产品为我砍了18个需求”的鸡汤课在哪报名,想报。"听懂掌声"的那种课就算了,太费手了。扯远了,回到我们今天的正题,我们了解下这篇文的目录。目录代码执行send成功后,数据就发出去了吗?回答这个问题之前,需要了解什么是Socket缓冲区。Socket缓冲区什么是socket缓冲区编程的时候,如果要跟某个IP建立连接,我们需要调用操作系统提供的socketAPI。socket在操作系统层面,可以理解为一个文件。我们可以对这个文件进行一些方法操作。用listen方法,可以让程序作为服务器监听其他客户端的连接。用connect,可以作...

今天又是被倾盆的需求淹没的一天。

有没有人知道,那种“我用3句话,就让产品为我砍了18个需求”的鸡汤课在哪报名,想报。

"听懂掌声"的那种课就算了,太费手了。

扯远了,回到我们今天的正题,我们了解下这篇文的目录。

目录
代码执行send成功后,数据就发出去了吗?

回答这个问题之前,需要了解什么是Socket 缓冲区


Socket 缓冲区

什么是 socket 缓冲区

编程的时候,如果要跟某个IP建立连接,我们需要调用操作系统提供的 socket API

socket 在操作系统层面,可以理解为一个文件

我们可以对这个文件进行一些方法操作

listen方法,可以让程序作为服务器监听其他客户端的连接。

connect,可以作为客户端连接服务器。

sendwrite可以发送数据,recvread可以接收数据。

在建立好连接之后,这个 socket 文件就像是远端机器的 "代理人" 一样。比如,如果我们想给远端服务发点什么东西,那就只需要对这个文件执行写操作就行了。

socket_api
那写到了这个文件之后,剩下的发送工作自然就是由操作系统内核来完成了。

既然是写给操作系统,那操作系统就需要提供一个地方给用户写。同理,接收消息也是一样。

这个地方就是 socket 缓冲区

用户发送消息的时候写给 send buffer(发送缓冲区)

用户接收消息的时候写给 recv buffer(接收缓冲区)

也就是说一个socket ,会带有两个缓冲区,一个用于发送,一个用于接收。因为这是个先进先出的结构,有时候也叫它们发送、接收队列

一个socket有两个缓冲区

怎么观察 socket 缓冲区

如果想要查看 socket 缓冲区,可以在linux环境下执行 netstat -nt 命令。

# netstat -nt
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0     60 172.22.66.69:22         122.14.220.252:59889    ESTABLISHED
这上面表明了,这里有一个协议(Proto)类型为 TCP 的连接,同时还有本地(Local Address)和远端(Foreign Address)的IP信息,状态(State)是已连接。

还有Send-Q 是发送缓冲区,下面的数字60是指,当前还有60 Byte在发送缓冲区中未发送。而 Recv-Q 代表接收缓冲区, 此时是空的,数据都被应用进程接收干净了。


TCP部分

【动图缓冲区的收发流程,TCP执行发收的流程】

我们在使用TCP建立连接之后,一般会使用 send 发送数据。

int main(int argc, char *argv[])
{
    // 创建socket
    sockfd=socket(AF_INET,SOCK_STREAM, 0))

    // 建立连接  
    connect(sockfd, 服务器ip信息, sizeof(server))  

    // 执行 send 发送消息
    send(sockfd,str,sizeof(str),0))  

    // 关闭 socket
    close(sockfd);

    return 0;
}
上面是一段伪代码,仅用于展示大概逻辑,我们在建立好连接后,一般会在代码中执行 send 方法。那么此时,消息就会被立刻发到对端机器吗?


执行 send 发送的字节,会立马发送吗?

答案是不确定!执行 send 之后,数据只是拷贝到了socket 缓冲区。至 什么时候会发数据,发多少数据,全听操作系统安排。

tcp_sendmsg 逻辑
在用户进程中,程序通过操作 socket 会从用户态进入内核态,而 send方法会将数据一路传到传输层。在识别到是 TCP协议后,会调用 tcp_sendmsg 方法。

// net/ipv4/tcp.c
// 以下省略了大量逻辑
int tcp_sendmsg()
{  
  // 如果还有可以放数据的空间
  if (skb_availroom(skb) > 0) {
    // 尝试拷贝待发送数据到发送缓冲区
    err = skb_add_data_nocache(sk, skb, from, copy);
  }  
  // 下面是尝试发送的逻辑代码,先省略     
}
在 tcp_sendmsg 中, 核心工作就是将待发送的数据组织按照先后顺序放入到发送缓冲区中, 然后根据实际情况(比如拥塞窗口等)判断是否要发数据。如果不发送数据,那么此时直接返回。


如果缓冲区满了会怎么办

前面提到的情况里是,发送缓冲区有足够的空间,可以用于拷贝待发送数据。

如果发送缓冲区空间不足,或者满了,执行发送,会怎么样?

这里分两种情况。

首先,socket在创建的时候,是可以设置是阻塞的还是非阻塞的。

int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
比如通过上面的代码,就可以将 socket 设置为非阻塞SOCK_NONBLOCK)。

当发送缓冲区满了,如果还向socket执行send

  • 如果此时 socket 是阻塞的,那么程序会在那干等、死等,直到释放出新的缓存空间,就继续把数据拷进去,然后返回

send阻塞
  • 如果此时 socket 是非阻塞的,程序就会立刻返回一个 EAGAIN 错误信息,意思是  Try again , 现在缓冲区满了,你也别等了,待会再试一次。

send非阻塞
我们可以简单看下源码是怎么实现的。还是回到刚才的 tcp_sendmsg 发送方法中。

int tcp_sendmsg()
{  
  if (skb_availroom(skb) > 0) {
    // ..如果有足够缓冲区就执行balabla
  } else {
    // 如果发送缓冲区没空间了,那就等到有空间,至于等的方式,分阻塞和非阻塞
    if ((err = sk_stream_wait_memory(sk, 
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭