TCP和UDPsocket中SO_SNDBUF和SO_RCVBUF_转 - yuxi_o - 博客园

1.Background

Winsock kernel buffer

To optimize performance at the application layer, Winsock copies data buffers from application send calls to a Winsock kernel buffer. Then, the stack uses its own heuristics (such as Nagle algorithm) to determine when to actually put the packet on the wire.
You can change the amount of Winsock kernel buffer allocated to the socket using the SO_SNDBUF option (it is 8K by default). If necessary, Winsock can buffer significantly more than the SO_SNDBUF buffer size.

send completion in most cases

In most cases, the send completion in the application only indicates the data buffer in an application send call is copied to the Winsock kernel buffer and does not indicate that the data has hit the network medium.
The only exception is when you disable the Winsock buffering by setting SO_SNDBUF to 0.

rules to indicate a send completion

Winsock uses the following rules to indicate a send completion to the application (depending on how the send is invoked, the completion notification could be the function returning from a blocking call, signaling an event or calling a notification function, and so forth):

  • If the socket is still within SO_SNDBUF quota, Winsock copies the data from the application send and indicates the send completion to the application.
  • If the socket is beyond SO_SNDBUF quota and there is only one previously buffered send still in the stack kernel buffer, Winsock copies the data from the application send and indicates the send completion to the application.
  • If the socket is beyond SO_SNDBUF quota and there is more than one previously buffered send in the stack kernel buffer, Winsock copies the data from the application send. Winsock does not indicate the send completion to the application until the stack completes enough sends to put the socket back within SO_SNDBUF quota or only one outstanding send condition.

https://support.microsoft.com/en-us/kb/214397

2.SO_SNDBUF & SO_RCVBUF

2.1基本说明

SO_SNDBUF
Sets send buffer size. This option takes an int value. (it is 8K by default).
SO_RCVBUF
Sets receive buffer size. This option takes an int value.

NoteSO stands for Socket Option

每个套接口都有一个发送缓冲区和一个接收缓冲区,使用SO_SNDBUF & SO_RCVBUF可以改变缺省缓冲区大小。

对于客户端,SO_RCVBUF选项须在connect之前设置.
对于服务器,SO_RCVBUF选项须在listen前设置.

2.2 Using in C/C++

int setsockopt(SOCKET s,int level,int optname,const char* optval,int optlen);

SOCKET socket = ...
int nRcvBufferLen = 64*1024;
int nSndBufferLen = 4*1024*1024;
int nLen          = sizeof(int);setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char*)&nSndBufferLen, nLen);
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&nRcvBufferLen, nLen);

TCP的可靠性

TCP的突出特点是可靠性比较好,主要是怎么实现的呢?
可靠性好不意味着不出错,可靠性好意味着容错能力强。
容错能力强就要求有 备份,也就是说要有缓存,这样的话才能支持重传等功能。
每个Socket都有自己的Send Buffer和Receive Buffer。
当进行send和recv操作时,立即返回,其实是将数据并没有发送出去,而是存放在对应的Send Buffer和Receive Buffer马上返回成功。

文献上send buffer的一点说明

udp send buffer

we show the socket send buffer as a dashed box because it doesn't really exist.
A UDP socket has a send buffer size (which we can change with the SO_SNDBUF socket option, Section 7.5), but this is simply an upper limit on the maximum-sized UDP datagram that can be written to the socket.
If an application writes a datagram larger than the socket send buffer size, EMSGSIZE is returned.
Since UDP is unreliable, it does not need to keep a copy of the application's data and does not need an actual send buffer.
(The application data is normally copied into a kernel buffer
of some form as it passes down the protocol stack, but this copy is discarded by the datalink layer after the data is transmitted.)”
(UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API,Pub Date: November 21, 2003)

根据以上《UNIX 网络编程第一卷》(此版本是2003年出版的,但是未查询到其它有效的文献)中的描述,针对UDP而言,利用SO_SNDBUF设置的值,是可写到该socket的UDP报文的最大值;如果当前程序接收到的报文大于send buffer size,会返回EMSGSIZE。

作用和意义

接收缓冲区

如何使用接收缓冲区

接收缓冲区把数据缓存入内核,应用进程一直没有调用read进行读取的话,此数据会一直缓存在相应socket的接收缓冲区内
再啰嗦一点,不管进程是否读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。
read所做的工作,就是把内核缓冲区中的数据拷贝到应用层用户的buffer里面,仅此而已

接收缓冲区buffer满之后的处理策略

接收缓冲区被TCP和UDP用来缓存网络上来的数据,一直保存到应用进程读走为止。

  • TCP
    对于TCP,如果应用进程一直没有读取,buffer满了之后,发生的动作是:通知对端TCP协议中的窗口关闭。这个便是滑动窗口的实现。
    保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。
  • UDP
    当套接口接收缓冲区满时,新来的数据报无法进入接收缓冲区,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。

发送缓冲区

如何使用发送缓冲区

进程调用send发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回
换句话说,send返回之时,数据不一定会发送到对端去(和write写文件有点类似),send仅仅是把应用层buffer的数据拷贝进socket的内核发送buffer中
每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。

SO_SNDBUF的大小

为了达到最大网络吞吐,socket send buffer size(SO_SNDBUF)不应该小于带宽和延迟的乘积
之前我遇到2个性能问题,都和SO_SNDBUF设置得太小有关。
但是,写程序的时候可能并不知道把SO_SNDBUF设多大合适,而且SO_SNDBUF也不宜设得太大,浪费内存啊(是么??)。

操作系统动态调整SO_SNDBUF

于是,有OS提供了动态调整缓冲大小的功能,这样应用程序就不用再对SO_SNDBUF调优了。(接受缓冲SO_RCVBUF也是类似的问题,不应该小于带宽和延迟的乘积)。

Dynamic send buffering for TCP was added on Windows 7 and Windows Server 2008 R2. By default, dynamic send buffering for TCP is enabled unless an application sets the SO_SNDBUF socket option on the stream socket.

较新的OS都支持socket buffer的自动调整,不需要应用程序去调优。但对Windows 2012(和Win8)以前的Windows,为了达到最大网络吞吐,还是要应用程序操心一下SO_SNDBUF的设置。

另外,

需要注意的是,如果应用设置了SO_SNDBUF,Dynamic send buffering会失效 。https://msdn.microsoft.com/enus/library/windows/desktop/bb736549(v=vs.85).aspx

将SO_RCVBUF SO_SNDBUF设置为0 没什么好处

Let’s look at how the system handles a typical send call when the send buffer size is non-zero.
When an application makes a send call, if there is sufficient buffer space, the data is copied into the socket’s send buffers, the call completes immediately with success, and the completion is posted.
On the other hand, if the socket’s send buffer is full, then the application’s send buffer is locked and the send call fails with WSA_IO_PENDINGAfter the data in the send buffer is processed (for example, handed down to TCP for processing), then Winsock will process the locked buffer directly. That is, the data is handed directly to TCP from the application’s buffer and the socket’s send buffer is completely by passed.

可以看出发送数据时,如果socket的send buffer(内核层)已满,这时候应用程序的send buffer(应用层)会被锁定,send 调用返回WSA_IO_PENDING。
当send buffer中的数据已经处理完,Winsock会直接处理锁定的send buffer(应用层)。也就是说,程序跳过socket的send buffer,直接处理程序的buffer(应用层)

The opposite is true for receiving data. When an overlapped receive call is performed, if data has already been received on the connection, it will be buffered in the socket’s receive buffer. This data will be copied directly into the application’s buffer (as much as will fit), the receive call returns success, and a completion is posted. However, if the socket’s receive buffer is empty, when the overlapped receive call is made, the application’s buffer is locked and the call fails with WSA_IO_PENDING. Once data arrives on the connection, it will be copied directly into the application’s buffer, bypassing the socket’s receive buffer altogether.

接收缓冲区的处理也是如此。

Setting the per-socket buffers to zero generally will not increase performance because the extra memory copy can be avoided as long as there are always enough overlapped send and receive operations posted. Disabling the socket’s send buffer has less of a performance impact than disabling the receive buffer because the application’s send buffer will always be locked until it can be passed down to TCP for processing. However, if the receive buffer is set to zero and there are no outstanding overlapped receive calls, any incoming data can be buffered only at the TCP level. The TCP driver will buffer only up to the receive window size, which is 17 KB—TCP will increase these buffers as needed to this limit; normally the buffers are much smaller.
These TCP buffers (one per connection) are allocated out of non-paged pool, which means if the server has 1000 connections and no receives posted at all, 17 MB of the non- paged pool will be consumed!
The non-paged pool is a limited resource, and unless the server can guarantee there are always receives posted for a connection, the per-socket receive buffer should be left intact.
Only in a few specific cases will leaving the receive buffer intact lead to decreased performance. Consider the situation in which a server handles many thousands of connections and cannot have a receive posted on each connection (this can become very expensive, as you’ll see in the next section). In addition, the clients send data sporadically. Incoming data will be buffered in the per-socket receive buffer and when the server does issue an overlapped receive, it is performing unnecessary work. The overlapped operation issues an I/O request packet (IRP) that completes, immediately after which notification is sent to the completion port. In this case, the server cannot keep enough receives posted, so it is better off performing simple non-blocking receive calls.

References:
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsockopt.html
UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API,Pub Date: November 21, 2003
http://blog.csdn.net/xiaokaige198747/article/details/75388458
http://www.cnblogs.com/kex1n/p/7801343.html
http://blog.csdn.net/summerhust/article/details/6726337

作者:FlyingPenguin
链接:https://www.jianshu.com/p/755da54807cd
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

缓冲区引出的问题:

1. 嵌入式 Unix-domain-socket详解UDP_skdkjzz的博客-CSDN博客

TCP和UDPsocket中SO_SNDBUF和SO_RCVBUF相关推荐

  1. tcp/ip协议中消息传输对帧消息的操作

    2019独角兽企业重金招聘Python工程师标准>>> 接口:Framer.java: package com.tcpip;import java.io.IOException; i ...

  2. TCP报文格式和三次握手——三次握手三个tcp包(header+data),此外,TCP 报文段中的数据部分是可选的,在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。...

    from:https://blog.csdn.net/mary19920410/article/details/58030147 TCP报文是TCP层传输的数据单元,也叫报文段. 1.端口号:用来标识 ...

  3. TCP/UDP编程中的问题汇总

    TCP/UDP编程中的问题汇总 TCP和UDP发送大文件的问题. 答: 发送端: 发送时,先发送文件的名称及大小等信息. 然后,设置一个缓冲区的大小,假设为4K. 再循环读4K的文件内容,并发送,直到 ...

  4. TCP 通信过程中各步骤的状态

    状态图 1 状态图 2 对于上面的图 N 多人都知道,它排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻的认识,不能只停留在 ...

  5. TCP/IP协议中的一些常用端口简单讲解

    (源自http://bbs.360.cn/3232114/17010996.html) 那么TCP/IP协议中的端口指的是什么呢?如果把IP地址比作一间房子 ,端口就是出入这间房子的门.真正的房子只有 ...

  6. 在TCP/IP模型中,( )处理关于可靠性、流量控制和错误校正等问题。

    在TCP/IP模型中,( C )处理关于可靠性.流量控制和错误校正等问题. A. 网络接口层 B. 网际层 C. 传输层 D. 应用层 TCP/IP模型的传输层提供端到端的通信,并负责差错控制和流量控 ...

  7. 【详解】以下关于TCP/IP协议栈中协议和层次的对应关系正确的是()

    以下关于TCP/IP协议栈中协议和层次的对应关系正确的是 解析: TCP协议和UDP协议都是基于IP协议的. 基于TCP的应用层协议:FTP.Telnet.SMTP.HTTP.POP3与DNS 基于U ...

  8. c++语言 tcp例子,C++中TCP通信实现文件传输

    作为Computer networks课程的一个project,我们需要实现用TCP在mininet中client和server的相互通信,需要能够传输文本文件,binary file 和image ...

  9. tcp码流中查找rtp头_跟踪数据流中的时间以查找性能问题

    tcp码流中查找rtp头 We're facing a challenge with several of our data flows that use more time than they ha ...

最新文章

  1. Facebook Messenger月用户数不断攀升 突破12亿
  2. WebPack在多页应用项目中的探索
  3. DMDW集群配置到DEM
  4. Nodejs之WebSocket
  5. 内存泄漏分析_调查内存泄漏第2部分–分析问题
  6. MP 启动注入 SQL 原理分析
  7. linux shell 函数 格式化,速查笔记(linux shell编程)
  8. 我的docker随笔33:在容器中连接oracle数据库
  9. Codeforces Round #467 (Div. 2)
  10. word把对应图片变成嵌入的ActiveX控件。
  11. 大数据在智慧城市中的应用有哪些
  12. surface 3安装android x86,Android-x86 9.0-r2稳定版发布 修复Microsoft Surface 3音频问题
  13. [读书笔记]iOS 7 UI设计 对比度
  14. 时间序列 ARMA 模型实战!
  15. MacOS删除开机启动项
  16. 二维码美化策略——QArt Codes
  17. 世界最早投入运行的计算机网络是,世界上最早投入运行的计算机网络是。
  18. 千字长文讲解系统架构,系统设计看这篇就够了
  19. 办理十环认证费用要多少钱?
  20. Vue开发之基础路由

热门文章

  1. 计算机网络之性能指标
  2. Flat-Lattice-Transformer模型源码测试
  3. 计算机 物联网 竞赛项目推荐
  4. 关于CIFAR-10图像分类总结
  5. 教师计算机网络培训总结报告,教师课件制作培训心得体会范文(精选3篇)
  6. opencv的多图拼接
  7. 高等数学--向量代数运算与模(八)
  8. 细节决定成败,数据中心标签管理的重要性
  9. STM32 时钟设置
  10. 英语自我介绍思维导图