要了解一个概念:所有的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的更多相关文章

  1. 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"

    [深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...

  2. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  3. Linux 网络编程(IO模型)

    针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...

  4. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  5. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  6. 【转】Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  7. linux网络编程九:splice函数,高效的零拷贝

    from:http://blog.csdn.net/jasonliuvip/article/details/22600569 linux网络编程九:splice函数,高效的零拷贝 最近在看<Li ...

  8. 《转》Linux网络编程入门

    原地址:http://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html (一)Linux网络编程--网络知识介绍 Linux网络编程-- ...

  9. 服务器编程入门(4)Linux网络编程基础API

      问题聚焦:     这节介绍的不仅是网络编程的几个API     更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系.     这节主要介绍三个方面的内容:套接字( ...

随机推荐

  1. dev grdicontrol 根据条件改变行颜色,字体颜色等

    dev grdicontrol 根据条件改变行背景   dev grdicontrol 根据条件改变字体颜色  dev grdicontrol 根据条件改变某个单元格背景 不用写代码  打开gridc ...

  2. [android开发之内容更新类APP]二、这几日的结果

    android教程即将開始 话说这开了blog之后,就一直在试用自己的app,发现.TM的真的非常不爽,不好用,好吧.本来打算放弃了.只是看到手机里还有还有一个坑,干脆又一次做一个吧. 原来的神回复A ...

  3. LDA-线性判别分析(四)

    本来是要调研 Latent Dirichlet Allocation 的那个 LDA 的, 没想到查到很多关于 Linear Discriminant Analysis 这个 LDA 的资料.初步看了 ...

  4. SQL-SERVER2008登录错误233

    问题 : SQL Server2008在本地使用Windows身份验证登录或是使用SQL Server身份认证登录时报错:已成功与服务器建立连接,但是在登录过程中发生错取.(provider:共享内存 ...

  5. css_day5

  6. Android 开源框架

    不推荐使用UltimateAndroid.KJFrameForAndroid.ThinkAndroid.Afinal.xUtil等这种集成网络请求.图片加载.数据库ORM.视图依赖注入.UI框架等的集 ...

  7. Windows Phone 学习教程(一)

    http://www.cnblogs.com/webabcd/category/385852.html Windows Phone 7 教程 Windows Phone 8.1 Windows Pho ...

  8. FZU1327 优先队列

    Problem 1327 Blocks of Stones II Accept: 318    Submit: 881Time Limit: 1000 mSec    Memory Limit : 3 ...

  9. hdu 2504

    Problem Description 有三个正整数a,b,c(0<a,b,c<10^6),其中c不等于b.若a和c的最大公约数为b,现已知a和b,求满足条件的最小的c. Input 第一 ...

  10. canvas总结:元素大小与绘图表面大小

    前言 我们使用canvas的时候一般在canvas元素中直接设置它的width和height: <canvas id="myCanvas" width="300&q ...