linux网络编程--跳水send和recv
要了解一个概念:所有的TCP socket在内核具有发送缓冲器和接收缓冲器。TCP除了全双工操作模式TCP滑模取决于这两个单独buffer和这个buffer填充状态。
接收缓冲器数据缓存入内核。应用进程一直没有调用read进行读取的话,此数据会一直缓存在对应 socket的接收缓冲区内。再啰嗦一点。无论进程是否读取socket,对端发来的数据都会经由内核接收而且缓存到socket的内核接收缓冲区之中。 read所做的工作,就是把内核缓冲区中的数据复制到应用层用户的buffer里面。仅此而已。进程调用send发送的数据的时候,最简单情况(也是普通情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回。
换句话说,send返回之时。数据不一定会发送到对端去(和
write写文件有点类似),send不过把应用层buffer的数据拷贝进socket的内核发送buffer中。
兴许我会专门用一篇文章介绍 read和send所关联的内核动作。每一个UDP socket都有一个接收缓冲区。没有发送缓冲区,从概念上来说就是只要有数据就发,无论对方能否够正确接收,所以不缓冲。不须要发送缓冲区。
接收缓冲区被TCP和UDP用来缓存网络上来的数据,一直保存到应用进程读走为止。对于TCP。假设应用进程一直没有读取,buffer满了之后,发生的动作是:通知对端TCP协议中的窗体关闭。这个便是滑动窗体的实现。保证TCP套接口接收缓冲区不会溢出。从而保证了TCP是可靠传输。由于对方不同意发出超过所通告窗体大小的数据。
这就是TCP的流量控制。假设对方无视窗体大小而发出了超过窗体大小的数据。则接收方TCP将丢弃它。 UDP:当套接口接收缓冲区满时。新来的数据报无法进入接收缓冲区。此数据报就被丢弃。
UDP是没有流量控制的;快的发送者能够非常easy地就淹没慢的接收者,导致接收方的UDP丢弃数据报。
以上便是TCP可靠,UDP不可靠的实现。
TCP_CORK TCP_NODELAY
这两个选项是相互排斥的,打开或者关闭TCP的nagle算法,以下用场景来解释
典型的webserver向client的应答,应用层代码实现流程粗略来说,一般例如以下所看到的:
if(条件1){
向buffer_last_modified填充协议内容“Last-Modified: Sat, 04 May 2012 05:28:58 GMT”;
send(buffer_last_modified);
}
if(条件2){
向buffer_expires填充协议内容“Expires: Mon, 14 Aug 2023 05:17:29 GMT”;
send(buffer_expires);
}
。
。
。
if(条件N){
向buffer_N填充协议内容“。。。
”;
send(buffer_N);
}
对于这种实现。当前的http应答在运行这段代码时。如果有M(M<=N)个条件都满足。那么会有连续的M个send调用,那是不是下层会依次向client发出M个TCP包呢?答案是否定的。包的数目在应用层是无法控制的,而且应用层也是不须要控制的。
我用下列四个如果场景来解释一下这个答案
因为TCP是流式的,对于TCP而言,每一个TCP连接唯独syn開始和fin结尾,中间发送的数据是没有边界的。多个连续的send所干的事情不过:
假如socket的文件描写叙述符被设置为堵塞方式,并且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的所有数据,那么把这些数据从应用层的buffer,复制到内核的发送缓冲区。然后返回。
假如socket的文件描写叙述符被设置为堵塞方式,可是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的所有数据,那么能拷贝多少就拷贝多少,然后进程挂起,等到TCP对端的接收缓冲区有空余空间时,通过滑动窗体协议(ACK包的又一个作用----打开窗体)通知TCP本端:“亲,我已经做好准备,您如今能够继续向我发送X个字节的数据了”,然后本端的内核唤醒进程,继续向发送缓冲区拷贝剩余数据。而且内核向TCP对端发送TCP数据,假设send所指示的应用层buffer中的数据在本次仍然无法所有拷贝完。那么过程反复。
。。直到所有数据所有拷贝完。返回。
请注意,对于send的行为,我用了“拷贝一次”,send和下层是否发送数据包。没有不论什么关系。
假如socket的文件描写叙述符被设置为非堵塞方式,并且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的所有数据,那么把这些数据从应用层的buffer,复制到内核的发送缓冲区,然后返回。
假如socket的文件描写叙述符被设置为非堵塞方式,可是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的所有数据,那么能拷贝多少就拷贝多少,然后返回拷贝的字节数。多涉及一点。返回之后有两种处理方式:
1.死循环,一直调用send,持续測试。一直到结束(基本上不会这么搞)。
2.非堵塞搭配epoll或者select。用这两种东西来測试socket是否达到可发送的活跃状态,然后调用send(高性能server必需的处理方式)。
综上。以及请參考本文前述的SO_RCVBUF和SO_SNDBUF,你会发现,在实际场景中,你能发出多少TCP包以及每一个包承载多少数据,除了受到自身server配置和环境带宽影响,对端的接收状态也能影响你的发送状况。
至于为什么说“应用层也是不须要控制发送行为的”。这个说法的原因是:
软件系统分层处理、分模块处理各种软件行为,目的就是为了各司其职,分工。应用层仅仅关心业务实现,控制业务。传输数据由专门的层面去处理,这样应用层开发的规模和复杂程度会大为减少。开发和维护成本也会对应减少。
再回到发送的话题上来:)之前说应用层无法精确控制和全然控制发送行为。那是不是就是不控制了?非也!尽管无法控制,但也要尽量控制!
怎样尽量控制?如今引入本节主题----TCP_CORK和TCP_NODELAY。
cork:塞子。塞住
nodelay:不要延迟
TCP_CORK:尽量向发送缓冲区中攒数据,攒到多了再发送,这样网络的有效负载会升高。
简单粗暴地解释一下这个有效负载的问题。
假如每一个包中仅仅有一个字节的数据,为了发送这一个字节的数据。再给这一个字节外面包装一层厚厚的TCP包头,那网络上跑的差点儿全是包头了,有效的数据仅仅占当中非常小的部分,非常多訪问量大的server,带宽能够非常轻松的被这么耗尽。那么,为了让有效负载升高,我们能够通过这个选项指示TCP层。在发送的时候尽量多攒一些数据,把他们填充到一个TCP包中再发送出去。这个和提升发送效率是相互矛盾的。空间和时间总是一堆冤家!!
TCP_NODELAY:尽量不要等待,仅仅要发送缓冲区中有数据,而且发送窗体是打开的,就尽量把数据发送到网络上去。
非常明显。两个选项是相互排斥的。实际场景中该怎么选择这两个选项呢?
再次举例说明
webserver,,下载server(ftp的发送文件server)。须在更大的带宽,server,使用TCP_CORK。
它涉及的互动server。实例ftp接收命令server。您必须使用TCP_NODELAY。缺省值是TCP_CORK。试想一下,。用户命令的每几个字节的敲,下保存数据。我想等到更多的数据发送前,这样的用户会等到发疯。
在最坏的情况下有一个特殊的词汇来描述-----棍(nian拼音第二声)包裹。
linux网络编程--跳水send和recv的更多相关文章
- 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"
[深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
- Linux 网络编程(IO模型)
针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- 【转】Linux网络编程入门
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- linux网络编程九:splice函数,高效的零拷贝
from:http://blog.csdn.net/jasonliuvip/article/details/22600569 linux网络编程九:splice函数,高效的零拷贝 最近在看<Li ...
- 《转》Linux网络编程入门
原地址:http://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html (一)Linux网络编程--网络知识介绍 Linux网络编程-- ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
随机推荐
- python之路-随笔 python处理excel文件
小罗问我怎么从excel中读取数据,然后我百了一番,做下记录 以下代码来源于:http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html ...
- xcode 执行时模拟器不可选的问题
好久没写博客了,上一次是什么时候都想不起来了. 之前总认为脑袋记住了,用过了就能够了,干嘛要写博客,简直浪费时间.事实上没事写写博客优点还是挺多的.这样既能够对自己用过的和学到的东西做一个总结,也能提 ...
- 关闭SQL Server 数据库所有使用连接
使用存储过程终止:在查询分析器下创建终止数据库所有接连的存储过程,通过调用该存储过程可以关闭所有使用该数据库的连接操作.--创建终止使用数据库下所有进程的存储过程,参数为数据库名称use maste ...
- IOS总结_无需自己定义UITabbar也可改变UITabbarController的背景和点击和的颜色
在application: application didFinishLaunchingWithOptions: launchOptions 增加以下代码就能够实现对tabbar的颜色的改动 //设定 ...
- windows下用vs2008和boost结合编译程序
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://co63oc.blog.51cto.com/904636/504469 win ...
- FOR UPDATE SKIP LOCKED
SYS_UNIT 中有UNIT_ID 0000000001 0000000002 0000001100 原意为若启用多线程,则每个线程在获取时仅可以获取一条数据(互斥) 脚本如下 1.SELECT * ...
- UIAlertView与UIActionSheet
1.UIAlertView(警告框) 1.1 创建警告框,设置样式 - (IBAction)alertView:(UIButton *)sender {//创建button按钮 //创建警告框的实例 ...
- ios 调用相机后 view 下沉问题
我只加了一句代码 现在不报错了 因为这个问题是随机性的 我也不太明白这个地方是怎么回事 我只是这样子做了 问题不出来了 if ([[[UIDevice currentDevice] syst ...
- 判断两个View的GRect是否相等
if (CGRectEqualToRect(self.view.frame, rect)) { // do some stuff }
- 原创+部分引用啦:C# Winform界面中的分隔线问题
C sharp 中Winform中的控件很多,一个小小的问题居然会绕上一个小弯子,做界面的时候, 你需要在界面上弄一条分隔线,把相关的功能分隔开来,结果原来在其它 IDE编辑器里很容易实现的这个功能, ...