所谓发送缓冲区和接收缓冲区,跟你自己定义的byte[]数组长度不是同一个东西

解决方案 »

  1.   

    如果您使用的是面向连接的协议,则 Send 将一直阻塞到发送完所请求的字节为止,除非使用 Socket.SendTimeout 设置了超时值。 如果超过超时值,Send 调用将引发 SocketException。 在非阻止模式下,Send 可能会成功完成,即使它发送的字节数比您请求的字节数少。 您的应用程序负责跟踪已发送的字节数并重试操作,直到应用程序发送了所请求的字节数。 不能保证发送的数据会立即出现在网络上。 为提高网络效率,基础系统可能会延迟传输,直到收集了足够多的传出数据后才开始发送。 Send  方法的成功完成意味着基础系统有空间来缓冲用于网络发送的数据。 
      

  2.   

    晕死,没写完就发出去了。我的问题1主要是:
    假设接收端不用Receive函数接收的话,接收缓冲区中最多能存8192字节,那么发送端世纪发送8192字节后接收端就不能再接收了,同时发送缓冲区中还能额外存储8192字节,也就是说,发送端一次发送81920000的数据,但实际能发送(包括拷贝到发送缓冲区)的数据最多为8192*2,但为什么却能返回81920000的数据全部发送成功?
      

  3.   


    嗯,我也看了这个说明。我确定我用的是阻止模式。现在的问题是Send函数返回的发送字节数就是81920000,但实际上不应该能发送这么多才对
      

  4.   


    嗯,我在大体说一下:
    问题1:假设接收端不用Receive函数接收的话,接收缓冲区中最多能存8192字节,那么发送端世纪发送8192字节后接收端就不能再接收了,同时发送缓冲区中还能额外存储8192字节,也就是说,发送端一次发送81920000的数据,但实际能发送(包括拷贝到发送缓冲区)的数据最多为8192*2,但为什么却能返回81920000的数据全部发送成功?问题2:ReceiveAsync函数为什么没有接收完数据就调用Completed回调了?而且结果显示这次接收是成功的?
      

  5.   


    就是接收端不用Receive函数接收数据
      

  6.   

    接收端能存多少和发送端发多少我觉得没有必然的限定条件的
    Complete也不是完全接收完数据才调用,接收一次就调用一次的吧?
    好长时间不接触Socket了,记不太清了
    你再扣一扣MSDN吧亲~
      

  7.   

    我觉得发送端能成功发送多少跟接收端的缓冲区大小应该是有关系的,不然81920000的数据发送成功了,那这些数据存在哪?
    另外,Completed回调如果不是完全接收完数据才调用,而是接受一次就调用一次,那这个接收一次如何界定?到底应该接收多少再调用Completed回调?目前如果需要接收的数据很大,比如81920000,则实际测试情况是不定的,就是说每次调用Completed回调时接收的数据大小是变化的,看不出什么规律;但如果接收数据大小小于缓冲区,则每次都是接收完所有数据才调用。唉,我现在头大啊MSDN上实在看不出什么东西了
      

  8.   

    1.Send成功仅仅是本机缓冲区可以装下,并不保证远程接受到数据。
    2.TCP仅仅保证数据的收发顺序,并不保证数据的收发批次,数据如何界定需要自己定义规则。
    3.系统缓冲区,不同的机器配置可能都不同。一般来说内存越大,缓冲区越大。
      

  9.   


    1、关键是目前本机缓冲区装不下还可以发送成功
    2、ReceiveAsync函数没接收完我指定大小的数据就调用Completed回调跟收发顺序和批次貌似没什么关系吧
    3、请问一般配置的计算机系统缓冲区有多少?大体是一个什么范围的值?感谢回答!
      

  10.   

    1.缓冲区并非socket对象的缓冲区,而是系统缓冲区。
    2.没接受完很正常,你可以继续接着收。
    3.这个没具体了解过,我2G内存的win2003只有几十MB,我16G的win7有几百MB,具体我也不清楚。
      

  11.   


    嗯,非常感谢!
    1、你说的是系统缓冲区,那么socket对象的缓冲区设置还有设么用呢?难道是先用系统缓冲区,用完后再用socket对象的缓冲区?
    2、从逻辑上来说,确实可以根据接收的返回结果循环接收直到要接收的数据完成,我只是想知道为什么会出现没接收完成就返回(调用Completed回调)的情况,因为从理论上来说,如果网络正常,是要完全接收完全才会返回的
      

  12.   

    1.socket对象的缓冲区用于接受数据,比如对方发了8MB,你只接受8KB,那么对方的其它数据就阻塞了。
    2.socket数据的收发都是以packet为单位的,大概在1KB左右,8M数据其实是8000+个包一个一个“慢慢”发送的。而接受数据的时候也是一个一个接受的,当网络没有跟上你的CPU的时候,也就是当前没有数据可以接受的时候,Receive就会返回了。
      

  13.   

    你这样理解一下
    你有一个server和一个client
    client给server发数据,使用的是sendclient.send之后,数据并不是真正的发送到了server,如果server还没有调用recv的话。这个时候,你send的数据,其实是保存在你的IO缓存里面了,当server调用recv之后,你的IO缓存中的数据被一点一点的发送给server,server也就一点一点的recv。
    关于你第二次send不反馈的原因是,你使用的tcp的流式传输,流式传输是需要保证数据的发送顺序的,因此你的IO在第一次send的数据还没有完全被server接收走之前,是不会接收你第二次send的数据的。至于你的异步send,不管你是不是用的IOCP,你send的TCP包都是有大小限制的,你的数据包每一次只能传输那么一点,至于多大,我记得好像是1000多个byte,忘记了。而异步socket就是为了解决同步不能立即反馈的问题,因此虽然你仍然使用的流式传输,但是你传输的数据,不管对方接受完毕没有,依然在给某个缓存中写入。
    但是因为tcp包只能那么大,所以你的每一次recv都只能接受部分,而不会全部接受完毕。告诉你一个现状,如果你是在本机测试server和client,那么你会发现你的client每次接受的数据量都是你定义的缓冲区的大小,只有最后快结束的时候不是。
    如果你的server和client在不同的机器上,那么你的client的recv并不是每一次都能接受到缓冲区那么多的数据,因为socket的IO缓存只有那么大,在你传输的时候,client电脑上的IO缓存还在接受其他的tcp包,不仅仅是你发送的tcp包
      

  14.   


    我没有看到哪里说过 Send 函数返回值是“发送成功”的意思。那就是.net 调用 windows 底层的 I/O 类库时对方返回的值,而这个值就是人家接收的数据的值。“第二次再发送就不会返回了”,显然也不是说什么“发送不成功”,不过就是暂时阻塞而已。没有哪里说过一个 SocketAsyncEvent 跟对方的 .net 程序的 Send 语句的 buffer 大小有关的。这是你自己想像的,肯定需要修正。反正你最好不要太大就行了。通常都需要做出“设计”决策。例如,当发送数据大于10M的时候,就不使用一个 Send 直接发送了,而是换其它信令(例如你们设计的断点续传命令)。
      

  15.   


    基本上,如果你在本地测试,那么只要你写 Send,一眨眼间,.net系统已经接收到了,只是你自己的代码没有读取而已。
    而这个81920000,只能代表着windows底层I/O层接受了这么多数据的发送请求,不一定代表着发送成功,至少不代表着对方的应用层程序已经读取。
      

  16.   

    有的人总是分不清楚底层跟高层机制的区别,可能是学点c语言学傻了吧,总是不能理解为什么会有这么多层系统封装。他以为“既然tcp包只有1000多一点字节大小”那么你在.net程序中把buffer设置为大于这个数也没用。实际上中间有一大堆系统在智能地处理,你怎么能知道你得.net程序会“卡在8192”这个死数上呢?你在发送端连续Send三个Buffer,第一个有1个字节,第二个有1999字节,第三个有81920000 字节,那么接收端可能会分别以81919990、2010字节两次才能接收到,或者或许接收5次才能接收到,这都很正常。发送和接收的buffer的大小,通常根据测试来调整。例如如果是pc,你可能设置为 1M,而不是100k。
      

  17.   

    回答了很多了,我就不参与了
    还是建议多看看MSDN,看看英文原版的,可能有些翻译成中文后让你无法理解了
      

  18.   

    呵呵,这么多人参与,非常感谢!
    以上几位提到了IO缓存的概念,是不是就是 sbwwkmyd 所说的系统缓存?我现在只想知道的是,在Socket类中是可以明确设定发送缓冲区的,那么也就是说在这个发送缓冲区外还有一个IO缓存,那还要这个发送缓冲区干什么?直接用IO缓存不久得了?Send函数返回是不是成功我是通过他的返回值来判断的,他的返回值只要是我要发送的字节数我当然就认为Send成功了(不管是真正发送了还是只是在发送缓冲区中),(Send 将数据同步发送到 Connect 或 Accept 方法中指定的远程主机,并返回成功发送的字节数,这是MSDN中文原话),那现在我只能认为那么小的Socket发送缓存却能发送那么大的数据成功(注意接收端没有接收数据)就是存在这个系统缓存上了,我只想确认这一点。至于接收端为什么没有接收完数据就返回了,其实我想这本来就是Socket的机制而已,就像 sbwwkmyd 所说的网络没有跟上你的CPU的时候Receive就返回了;但我纠结这个问题是因为这种表现跟MSDN的说法不一致,
    MSDN中文原话为:
    如果没有可读取的数据,则 Receive 方法将一直处于阻止状态,直到数据可用,除非使用 Socket::ReceiveTimeout 设置了超时值;
    另一句话为:
    如果当前使用的是面向连接的 Socket,则 Receive 方法将读取所有可用的数据,直到达到 size 参数指定的字节数。按这个理解,在网络正常且没有设置超时的情况下, Receive 自然是要等到读取到我指定Size的所有数据后才返回,无论等多久。
      

  19.   

    Receive 自然是要等到读取到我指定Size的所有数据后才返回
    -------
    不是的.如果发送的数据多余你指定的size,到了size就会返回
    而如果发送的数据少于你指定的size,则此次发送接收完整了就会返回
      

  20.   

    比如发送端发送1个字节,而接收端size设置为1000,也是直接接收到1个字节,而不是等发送端发送了1000次之后才返回
    这个size只是指定了"一次最多接收多少个字节",而不是每次至少接收多少字节
      

  21.   


    嗯,目前这个说明最明确。
    那我只能理解MSDN的说法是:调用Receive 时如果没有数据可读则将阻止直到有数据可读,至于实际读多少数据在于当前有多少数据可读而不在于我指定需要读多少数据;也就是说,这里所说的阻止只是说没有任何可读数据时会阻止而不是说没有足够数据时会阻止。
      

  22.   

    系统缓冲区与socket对象缓冲区,一个是公用的,一个是私有的,是两个层面的东西。
    从架构设计的方面考虑的话,你不应该把私有缓冲区设置的太大。如果没有系统缓冲区,当你发送的数据量大于私有缓冲区的时候,不会想要自己去循环处理吧。
    当然系统缓冲区也有大小,当阻塞的数量太多的时候还是需要自己循环处理,但是它满足了一般情况。
      

  23.   

    非常感谢 sbwwkmyd 给出了最明确的解答。
    也很感谢各位的参与。最后说一句,有时候MSDN也是个坑爹的货
      

  24.   

    看MSDN,有时候需要看英文原版,而不是看翻译出来的意义不明确的东东