socket s;
char* buf=new char[100000];1.循环send(s,buf[nPosition],100,0),直至将buf中的所有数据即100000字节全部送出;
2.send(s,buf,100000,0)请问:1和2在网络传输效率上有无区别,区别在哪里?

解决方案 »

  1.   

    回复人: fhqiplj(霏霏鱼) ( ) 信誉:98  2005-06-27 13:11:00  得分: 0  
     
     
       可能第2种的效率高一些,系统自己处理分组的时候应该比自己处理快
    而且第1种还有一个返回处理,可能会慢一些
      
     
    未抓住实质,等待达人解答。
      

  2.   

    send只是把数据放入系统的发送缓冲区,真正的数据发送并不一定立即开始。
    所以,一次放入少量数据,首先增加了函数调用的次数,
    增加了系统缓冲区分配的额外计算负担,另外,会影响系统对包大小的有效计算。
    一次放入大量数据,系统缓冲区空间可能不够用,所以send(s,buf,100000,0)
    并不一定把100000个字节都放入系统缓冲区,这种调用本身就是病态的。
    典型的IO方法是这样的:
    socket s;
    char* buf=new char[100000];
    unsigned int totlelen =100000 ;
    unsigned int sendlen;
    do
    {
        sendlen = send(s,buf,totlelen ,0);
        totlelen -=sendlen ;
    }while (totlelen >0);
    接收数据同发送数据类似。
      

  3.   

    softrain(敢笑杨过不痴情)的解答还需加入fhqiplj(霏霏鱼)所说的返回处理,
    do
    {
        sendlen = send(s,buf,totlelen ,0);
        if(sendlen == SOCKETERR)
       {
         int err = WSAGetLastErr();
         if()
         {
          }
       }
        totlelen -=sendlen ;
    }while (totlelen >0);
      

  4.   

    上面讲的都是TCP的情况  针对UDP 该如何了?
      

  5.   

    感觉楼上各位的回答,似均未触及我想了解的实质性问题。
    我这样阐述或许要清晰一些:
    socket s;
    char* buf=new char[100000];1.循环send(s,buf[nPosition],100,0),直至将buf中的所有数据即100000字节全部送出;
    2.send(s,buf,100000,0);
    请问:1和2分别被操作系统用分几次(或几个包)在网络上传输完成,此两种方式在网络传输效率上有的区别哪里?注意,此处不用论及多次send()调用的cpu开销,特问网络传输效率?
      

  6.   

    send(s,buf,100000,0); >=  循环send(s,buf[nPosition],100,0)
    前者保证可以用MTU的包发出去,而后者有些包可能达不到MTU。
    试想有一个漏斗,一次放一大瓢水放进去漏的快,还是一次放一汤匙漏的快些?
      

  7.   

    回复人: softrain(敢笑杨过不痴情) ( ) 信誉:98  2005-06-28 16:33:00  得分: 0  
     
     
       send(s,buf,100000,0); >=  循环send(s,buf[nPosition],100,0)
    前者保证可以用MTU的包发出去,而后者有些包可能达不到MTU。
    试想有一个漏斗,一次放一大瓢水放进去漏的快,还是一次放一汤匙漏的快些?
      
     
    若send()一段数据,而此段数据未达MTU,那么此段数据什么时候能被操作系统发送出去,望有人能深入谈下这个问题。
      

  8.   

    其实分两个方向考虑吧.
    1.代码执行的时间. 多次调用自然比不上一次调用的性能好了,执行的代码量也多嘛.
    2.网络发送的时间.从程序缓冲到内核缓冲这个过程,有一个复制的过程吧?当程序缓冲的size大于内核缓冲,那自然是需要分多次的复制才能完成的,不过这样的话可以得到最少的复制次数.如果是非阻塞式的话.估计很麻烦,因为会发送失败.
    这是针对tcp的.如果是udp,如果太大.嘿嘿.有可能发送失败,另外,udp最大的缓冲区也是有限制的(linux最大是64KB ?).不像tcp会自动分片发送.
    我猜的,没有试过大数据量的发送.达人来说说看.
      

  9.   

    若send()一段数据,而此段数据未达MTU,那么此段数据什么时候能被操作系统发送出去,望有人能深入谈下这个问题。
    --
    tcp是以窗口大小发送的吧.由网络状态决定,应该不是由MTU决定的吧
      

  10.   

    send()函数本身也是有消耗的,减少send()函数的调用次数,可以提高程序效率。
      

  11.   

    send把数据投递到系统缓冲区,系统不是立即把数据发送出去,而是稍微等待一下,这个时间非常短,而且也是动态变化的。在这个时间内,如果数据量达到值得发送的大小了,它会把发送数据出去,否则会等到限定的时间,即使有非常少量的数据也会把数据组包发送出去的。设置这个时间就是避免每次发送少量数据造成传输效率低下。对于MTU,也是系统动态试出来的,每次发送数据时IP层都是把数据段尽可能地按照MTU的值打包发送出去。
    比如100000的字节都按照MTU=1000发送需要发送100次,如果按照小于1000的值发送就要大于100次。谁快谁慢不言而喻。
      

  12.   

    "send把数据投递到系统缓冲区,系统不是立即把数据发送出去,而是稍微等待一下,这个时间非常短,而且也是动态变化的。"请问softrain,“这个时间非常短,而且也是动态变化的",这个时间具体是多少,若其动态变化,这个时间又会是多少。
      

  13.   

    只要你多次send的包大小,是实际发送时tcp包的整倍数大小,应该不影响效率吧?
    反正你必须判断send的返回值,太大了,还是得分多次发送。没用的。
      

  14.   

    softrain(敢笑杨过不痴情) 
    已经说得很清楚了
    看得出他很了解网络的底层
    建议你使用第二种方法
    send(s,buf,100000,0);
    由系统自动去发会比你自己控制好
    正如softrain所说MTU是系统动态试出来的
    你很难知道用户现在网络的MTU呵
    TCP的流控做得挺好的
      

  15.   

    哎!看高手们聊的起劲,偶也来说说,偶最近也在做UDP传输文件的程序,谈谈楼主的问题,我个人觉得一次发送,比循环效率高,但是重根本来讲,TCP是可靠传输,适合传输大型且安全性强的文件,UDP是无连接协议,适合传输小型不需要考虑安全的文件,楼主应该明白了吧,一次发那么大的文件用TCP是小事,如果换UDP也没问题,但是考虑到更深层的,关于系统自己处理缓存等方方面面,以及网络状态等因素,可以说,一次用UDP发出去有点不妥,所以我们发大的文件还是用循环多发几次,在处理分包,发包,收包,校验,组包,这样就可以很可靠的将文件送过去了,其实这个速度并不是很慢,如果网络好,机器好等等,会比一次发过去要可靠的多!效率当然也就没什么区别了
      

  16.   

    如果是UDP
    是不能一次性发那么大的
    会失败
    而且用UDP的话
    需要处理丢包的情况
    根据传输的大小有不同的方法来处理
    不过要自己去处理丢包的情况
    实在是麻烦,
    处理方法不对,效率更低
      

  17.   

    没有达到MTU的,如果你设置了TIME_NODELAY就立即发送,如果没设置TCP就自动等到达到了MTU再发送
      

  18.   

    godfly000说:
    "没有达到MTU的,如果你设置了TIME_NODELAY就立即发送,如果没设置TCP就自动等到达到了MTU再发送“。如果既未设置TIME_NODELAY,又没达到MTU,这段数据岂不是不能被传输?
      
     
      

  19.   


    说到TCP对发送数据的控制涉及到TCP段、IP包的组织方式和TCP的诸多流控制算法(如拥塞控制算法)等的实现。你可以让所有的包都分成不超过MTU的512字节但你还是不能保证在传输到客户端过程中不会被再次分割,只要存在分割,就会出现包的丢失风险,效率肯定就比你先前预定的512字节或者10字节更保险的数据大小传输效率要低,但你又考虑到网络带宽的利用率对于你每次512字节或者10字节的传输效率相比是否也是效率不高呢?这是永远矛盾的东西,关键是看你要怎样的平衡。其实这是个对编程透明的问题,是属于操作系统自行决定处理的。所以说,楼主的对这个问题的讨论是空泛而注定不会有任何结果的。
      

  20.   

    这个问题其实没什么难的,楼主自己看看《TCP/IP详解》第一卷就会明白的。一次发送肯定比循环发送的发送次数要少
    一次发送的发送包量=数据量/MTU
    循环发送的发送包量=数据量/自定义每个包的大小当自定义每个包的大小>MTU,tcp会将其分割,结果发送次数还是比一次的要多,发送次数越多,就越慢,特别实在广域网上很明显。关于NODELAY,就是Nagle算法
    就是缓冲中的数据不是立即发送,而是等待一定的量或规定的时间到了就会发送。关闭后(设置NODELAY)效率会降低。楼主所问的“如果既未设置TIME_NODELAY,又没达到MTU,这段数据岂不是不能被传输?”
    因为他还有时间间隔,好像是200ms,间隔到了就发送。具体算法你要看看书上说的,这里很多说法我认为并不准确,包括我自己的见解。
      

  21.   

    对于楼上的“当自定义每个包的大小>MTU,tcp会将其分割”这一点有点异议,当自定义每个包的大小>MTU,负责分割的应该是在IP层而不是在TCP层吧。仅提出自己的个人看法,与大家商榷。
      

  22.   

    send(s,buf,100000,0)实际效率高!
      

  23.   

    to  HiIM() “MTU,负责分割的应该是在IP层而不是在TCP层吧。仅提出自己的个人看法,与大家商榷。”============================================不是在ip层,就是在tcp层,否则将会出现ip包分片,这是tcp不允许的!tcp将会根据MTU值来分割tcp数据包,然后传给ip层,否则和UDP一样了
      

  24.   

    to  yzkzero(Skall You):1、如果在tcp层进行IP包的分割,请问在TCP头的什么地方知道分割点、分割偏移等数据?2、分割标志等IP包分割控制在TCP层的什么地方存储:MTU是否是与链路层直接交互的IP包有关,而与TCP段以上的TCP层是通过网络层来通讯的。
      

  25.   

    to HiIM() 首先,要发送的数据传到TCP层,TCP将其按照MTU值分割数据,将分割好的加个TCP头变成报文段,IP再将该段加上IP头变成IP数据报。×TCP头部的32位序列号标识了报文段中的第一个字节的“偏移”TCP是流式传输数据,所以并没有数据包结束的概念,你发送了50k数据后再发送30k数据最于接受者而言,只知道来了80k数据。×所以分割标志对TCP而言没有意义,也并不存在。分割标识只是对于IP数据报而言的,比如UDP传给IP层,要发一个10k数据,这时IP层就会将其加上IP头,变成一个10K的数据报,发送时发现它比MTU大,于是就要分片发送,但IP头只在第一个分片中。(而TCP传给IP的数据肯定小于MTU+IP头,所以IP数据报不会分片)
    关于其他详细的,请看一下《TCP/IP详解第一卷》,很多具体内容我记不得了,你还是自己看一下书吧。
      

  26.   

     学习 高人
    一定看一下 TCP/IP详解
      

  27.   

    to  yzkzero(Skall You):你基本概念错了,MTU只与IP包发生联系,而MTU是与Link Payer有关系,与TCP段没有联系。TCP所在的传输层只通过滑动窗口来控制网络流量。
      

  28.   

    笔误:Link Payer应该是Link Layer
      

  29.   

    to HiIM() MTU的确是与IP包相关,但TCP会根据这个值来分割数据的,书上有说的,滑动窗口是另一个概念。如果阁下坚持自己的看法,不如看看我所推荐的书再来讨论好吗,否则再讨论下去也很难说清楚了。
      

  30.   

    你所说的重要依据路径MTU,TCP/IP详解上说的并不清晰。
    关于路径MTU发现你可以参考RFC1981文档,该文档描述了对于IPv6的路径MTU探索。它很大程度上是从RFC1191(描述了对于IPv4的路径MTU探索)发展而来的。而在其
    “5.4 TCP层动作
    TCP层必须通过一种连接记录路径上的PMTU;它不能发送可能导致分组大于PMTU的分段。一个简单的执行过程应当在每次建立新的分段时询问IP层相应的值,但是它的效率很低。”
    里已经很明确指出了TCP是必须“询问IP层相应的值”。就是说,IP层里才有保存分割信息的起码数据结构,你先看看IP头的结构与TCP头的结构就会明白。在TCP头里根本没有Fragment Offset(13-Bits)和分割Flags(3-Bit)。你回帖里写的“×TCP头部的32位序列号标识了报文段中的第一个字节的“偏移””的TCP头部的32位序列号其实只是标志数据流的32-Bit Sequence Number。与IP头里的Fragment Offset(13-Bits)分块偏移根本是两个概念,不要被弄混淆了。
      

  31.   

    to HiIM() 是啊,所以我的偏移是打引号的,它的作用就是用来接到数据报后,用来拼接完整数据用的,所以从含义而言,用“偏移”来表示。“在TCP头里根本没有Fragment Offset(13-Bits)和分割Flags(3-Bit)。”的确是没有这两个东西的,我没说TCP有这两个东西啊,他们是IP数据报的。=========================================阁下似乎是误解我的意思了,我所指的TCP分割数据和IP数据报的分片是两个概念我这样描述把你send(1k),这时1k数据被放入tcp缓冲区,然后tcp发现MTU是800,随后,他会设置一个值叫做MSS(Max Segment Size),他的数值=MTU - IP head - TCP head = 800 - 20 - 20 = 760,接下来就是将1024的数据分成两份,760和264,然后将760的加上TCP头部,变成一个TCP数据报,传给IP,IP层再加上一个头变成IP数据报,这时,IP层发现数据报=800,<=MTU,所以不分片就发送出去了,而264的也是同样的步骤接着发送出去的。通过这个过程,可以看出,tcp无需什么分割标识,它每次发送的大小都=MSS,除了最后一个小包。我还要说明一点,就是我上面说过的,他是流式数据,没有界限的概念,所以更本就不可能有什么类似IP包分片(分割)的概念,发送逻辑上不同的两段数据,对于TCP而言都是一样的,就像一倍牛奶倒倒漏斗,再倒一杯可乐,对于漏斗而言都是流体,它只管流出去。
    TCP的32位序列号就是用来标识顺序的,比如上面的760的标号=1,264标号=2,他们到达目的地就会按照标号来重新组织起来。
    这样说,阁下清楚了没有?还有,阁下的理解我是越来越不懂了,如果阁下愿意,可以将你的理解详细说一下。
      

  32.   

    HiIM已经写得很清楚了。看来对于这个问题两位高手没有讨论下去的必要了,都散了去吧,呵呵
      

  33.   

    肯定是一次效率高,让内核帮你发送。
    所以microsoft建议在适当的地方使用TransmitFile。
      

  34.   

    TransmitFile效率是高,但是无法显示进度啊,而且可控性很差,也无法实现续传。
      

  35.   

    一次发送是不行的,这里面有一个问题就是I/O的效率问题,也就是说,I/O的效率在何种情况下最大。我们在处理TCP连接的时候,一般不需要考虑MTU,因为这个值不是确定的,要根据具体的网络情况来定。那么首要的问题就是我刚才说的那个I/O效率问题了。一般从经验上来看,8k是最为理想的了,而且Windows下的默认缓冲区大小也就这个数。将100000大小的数据分成每份8k,会得掉比较好的效率的。
      

  36.   


    Nagle算法不仅仅是根据MTU来决定是否发送数据的。比如间隔500ms以上,你即使发送1bit,网络层也会立刻把这1bit的数据发送出去。接着你第二次发送1bit数据,Nagle算法就启用MTU控制了。