我是分次发送的呀.每次5210字节(实际上减去8个字节的包头),测试用的文件kangjia.mpeg文件大小为2.642388m.
如果我在strea.write(buffer,0,buffer.length)前设断点,循环几次后取消断点完全放行,则复制过去的文件大小完全正确,可正常播放.但是,如果我从开始时就不用断点,则总是会少四五个包,使得传过去的文件无法播放.
同样.如果我在tread.write(buffer,0,buffer.length)前加上tread.sleep()暂停200毫秒,发送接收也完全正确,收到的文件可以正常播放.搞不明白什么愿因

解决方案 »

  1.   

    可是,write是阻塞的呀,我原以为只要接收方没有执行stream.read()的话,发送方会一直阻塞在stream.write()处,但根据出现的这种情况来看,这个远程传机制有点不对劲 !
    我观察,实际上,当程序运行到nwStream.write()时,即使接收方没有执行streamWrite(),程序也会继续执行nwStream.write()五六次左右,如果接收方还是没有执行read(),发送方才会阻塞挂起..并非直接阻塞.
    但不管理怎么说,从write会因为接收方不读而挂起这种现象来看,接收速度是会影响到发送速度的,按此理,发送方不可能在接收方没有读出流中的数据的情况下跳过流中任何数据而发送后面的数据的.
    可事实上,为什么在阻塞状态下执行的TCP数据传输,怎么会在前面的包没有被成功接收的情况下继续发送后面的数据,这那里阻塞了呀
      

  2.   

    同志们,一起努力解决这个问题吧.
    难道一定要一问一答,请求一个位置发送一个位置吗?不断向发送端发出请求的数据的序号,例如,请求"1",就发第一个包,请求"2"就发第二个包....,如果请求2,结果没有收到2号包,超时后再次请求包2;如果收到了包3,则继续发送请求包2的信息,总之,由下载方完全控制发送方的发送步骤.
    帮我想想,一定要这种做才可能不丢包吗.
    可如果这样做了,效率一定高不了.按理说, netWorkStream,接受方应该在每一次执行完read后,向彼岸发送方发出一个成功读取的信号,然后发送方才向网络流中继续写入,如果发送方收不到彼岸的读完信息,则会一直保持阻塞,如果超时,且重发前一个数据等等.
    可是,实际上,networkStream似乎在流中的数据没有被读取的情况下,连续发送五六个数据包.总之 ,我还是没搞明白,为什么在执行writ()函数之前,必须要进行延时处理才能保证数据不丢失?
    那几个数据包到底是在那个环节里丢失的呢?是TCPclieng的BUG还是露洞,还是说我采用了错误的方法?
    还有就是,DataAvailable 在什么情况下算是有数据状态true,什么情况下会是false?有数据到底是什么意思?意味着什么?
      

  3.   

    既然你用了循环, 就不要BeginWrite了, 直接Write
      

  4.   

    楼上的,这里讨论的是数据比较大的传送(>1M)。
    一定不可以一次搞定的。从以前的帖子里翻出来的,参考参考。http://topic.csdn.net/t/20060720/09/4892211.html
      

  5.   

    我觉的这个问题根源在接收方,TCP的同步发送返回只是说明数据已经交给底层的Socket缓存,Windows的Socket机制应该能够确保所有的缓存数据都会被发送,但比不表示同步发送返回,该数据块就已经被接受方接收了。当接受方接收数据过满,缓存写满后就会发生后续数据丢失的问题。
      

  6.   

    to:dionix
    看得出来您对soket很有研究,先谢谢!
    可是我有一点不理解,如果接收方的soket缓存满而未被读出时,底层soket机制应该停止将数据转移到接受方的缓存才对,否则,就很大程序上失去了数据在传输中的安全性,而tcp的特点就是安全,否则,还不如用udp呢.可如果按您所言,接收方的缓存写满后是丢失数据而不是通知发送方的底层停止发送,那数据发送过程中的安全性何以保障?毕竟两台机器的硬件条件差异是巨大的.比如我的机器 ,一个是P43G,一个是双核1.7G,不知道是不是和这个有关系?
    另外,我今天调试时发现,主要是前几个包丢失,后面基本上没发现丢失问题.我在向网络流中写入之前加入了:
                int n = 0;    //用以帮助执行sleep            while (( nReadLength = streamLocalFile.Read(buffer, nOffSet, nDefaultDataLength )) > 0)  //直到读到数据的结尾
                {                
                  .....
                    if (n < 4 )
                    {
                        Thread.Sleep(200);
                        n++;
                    }
                    //nwStream.Write(buffer, 0, buffer.Length);  
    ...然后,就很少写丢包.但如果把这个4改成0,就肯定丢包,改成1,丢包会少一些,希望这个线索能启迪高手给点提示.
      

  7.   

    谢谢Ezhuyin给的回复,看了看,很有得学习.多谢!
      

  8.   

    经过断点测试,我如果先放行接收方的断点,然后再放行发送方的断点,接收数据成功,数据无丢包.
    而如果我先放行发送方,任发送方向流中写入数据,则发送方会连续写入,而此时再放行接收方,第一个数据包肯定丢失.
    另一种通过观察数丢的方式来看,如果发送方不设断点,接收方在第一个数据体(算上文件头包的话,这个包应该是第二个包)中接收的数据包中的数据就不对,也就是说,第一个包丢失了.
    还有一种现象,就是,当发送方非断点畅通执行,接收放每收到一个包断点,手工放行,则接收方从网络流中读出的数据全是空包,里面的字节全为0.(按理说,如果发送方没有向流中写入空包,不可能从流中读出空包.
    由以上现象来看,底层soket的阻塞执行机制可能真的有问题.在接收方数据速度够快的情况下,接收正常,如果接收方读流的数据赶不上发送方向流中写数据的速度,那么,接收方从流中读出的数据就可能出现以下情况:一,在还没有读出B的情况下直接读出了C,且B将一直被勿略,就像发送方从来没有将其放入流一样;二,从流中读出的数据字节全为0有经验的朋友帮我找找解决方案,
    如果我直接用soket而不用tcpclient和networkstream收发的话,有没有可能避免这个问题呢?还望大家帮忙
      

  9.   

    我偿试:
    直接执行接收端和发送端的exet程序,偿试发送十次同一个2.51m的视频文件,约有2次左右没有丢包,成功传送;5-7次丢1个包,而且是第一个包,因为视频文件如果丢了第一个包就无法播放了,丢后面的还可以播放.还有2次左右丢稍多一些的包
    在这个测试中我没有使用thread.sleep(),完全使用tcpclient和networkstream的机制传送.过程大概为:
    发送方:
    -----读本地文件到缓存中
    ----写缓存中的数据到网络流中
    --循环接收方:
    -----从网络流中读出数据到缓存
    -----将缓存中的数据写入本地文件中
    -----循环发送方缓存大小:5120
    发送方网络流缓存大小:5120
    接收方缓存大小:5120
    接收方网络流缓存大小:5120同志们帮我想想,看到底是TCPclieng\networkstream的问题,还是soket的问题,还是说我程序代码的问题 .此问题不搞清楚,试想谁也把一个每次执行结果都不一样的文件传送模添加到自己的项目中呀.
    先谢谢同志们了.
      

  10.   

    再补充一下
    我两台电脑在一个局域网hub下.一个P43.0g,一个core2双核1.7G.前者512内存,后者1G内存.不知道有没有可能会是硬件性能差异造成的,如果是,那到底是那个层而设计不合理造成的
      

  11.   

    LZ,不知道你在发送方为什么用BeginWrite,这样是异步发送,我觉得应该尝试改成Write,可能就会有改善,这样试下://发送方:nwStream.BeginWrite(buffer, 0, buffer.Length, asyncCellback, nwStream);改成:nwStream.Write(buffer, 0, buffer.Length);
      

  12.   

    to 红金鱼:
    不好意思,这是测试忘记改回来了,实际上用的不是begin.谢谢提醒.终于找到了能解决问题的方法:把缓存降到了2048以下,正常不设断点没出过错,但好像如果只有接收方设断点,而发送方不设断点直接运行,还是会出现.虽然问题基本解决,但知其然而不知其所以然总也不是回事.为什么一定要降到2048以下才不会问题?丢问到底是那个环节的问题?如果换了其它硬件环境会不会还出现丢包?等.所以说,我目前能确定的一件事是:TCP协议默认方法并不是绝对不丢包的,和硬件有一定关系.最起码,如果把缓存置的太大,就可能会有包不能被接收方读到.真正可靠的数据传输可能只能在应用层上采取措施了.要不然,到时候程序发布出去了,发送视频或其它文件到远程主机,结果有些能播有些不能播,那可麻烦就大了.有相关经验的朋友提点建议
      

  13.   

    发送基本上没有问题,主要看接收方是怎么处理的。有时候全部发出的数据,接收时会丢失一部分。如果你用Socket发送一个大于10MB的文件或数据到一个SMTP邮件服务器,则一点问题都没有。目前你收完数据库不能播放,则可能是接收时丢失了数据。
      

  14.   

    能告诉我你代码里的nCommand_Head这个变量是什么吗?
    我现在也在做tcp上传,但我不知道nCommand_Head这个是什么意思。
      

  15.   

    后来你到底怎么解决的?为啥坚持用tcpclient和networkstream的机制 而不用socket呢?它们优势在哪儿呢?
      

  16.   

    tcp是不会丢包的。 接收的时候收到的实际大小会不同