基于TCP通信方式的socket收、发文件:1:一个比较大的文件(比如10M),socket发送时,为什么一般采用循环多次发送呢?也就是多次send。但是,IP/TCP协议不是已经在底层,把数据分成多次和多个小包发出去了吗?为什么应用层还要多次发送,而不采取一次性发送(即只调用一次send函数);
2:如果A---->B(此时A和B已经建立好连接),A向B发送数据, 即:A端send,但是B端并不接受数据,即没有调用recv函数。
那么A端的send成功否? 是send成功、失败?还是底层协议发送数据成功或失败?
 好像还有个什么socket缓冲区,什么满了就不能继续发送了?对于上面这些疑问,请各位大侠老师帮我这个菜鸟讲解一下,很感谢很感谢!

解决方案 »

  1.   

    1.虽然说分包是在底层,但是如果你一次发送10m的话,网卡没有那么多缓存来保存你需要发送的数据,所以send并没有把所有数据放到网卡缓存里,只能存入部分;
    2.没仔细研究过,不太清楚
      

  2.   


    就是这个意思了,而且每次发送的数据量都不一定相同的,只能依据发送的量来计算,当你只发时不接当然会失败的啊,第一个你可以通过发送的返回值来判别再一个若发送失败的话好像可以用GetLastError获得那个错误提示吧,没用过,呵呵
      

  3.   

    1 分包是由 Nagle算法决定的, Nagle通过减少发包数目来提高网络软件的效率. 你可以选择关闭
    2 你可以判断Send返回值的, 很多可能的, 比如你发送端发送成功了, 服务端有粘包的情况
      

  4.   

    和你机器配置没有 多大关系和你的操作系统有关socket缓冲区大小系统有默认设置,可以修改,一次开辟10M的缓冲区,你可以测试下效果就知道了既然建立了连接,B端默认是接收数据的如果你想检查传输数据的完整性,可以测试下:A发送数据给B,此时A等待接收B的返回数据,B接收完毕检查后,发送数据给A,A根据B返回的数据确认是否重新发送。
      

  5.   

    问题1大家都回答过了,我来答问题2吧2:如果A---->B(此时A和B已经建立好连接),A向B发送数据, 即:A端send,但是B端并不接受数据,即没有调用recv函数。
    那么A端的send成功否? 是send成功、失败?还是底层协议发送数据成功或失败?
     好像还有个什么socket缓冲区,什么满了就不能继续发送了?就算没有调用recv函数,send照样成功的我帮你查了资料得到的理解是:
    1.端口(假设s3000)处于listen状态,客户端connect通过三次握手,完成之后就确定两者之间是可通的,也就是说客户察觉到服务器的确开了一个端口在listen,并且我们可以对这个端口进行发送数据;
    2.服务器端与客户端的路由表只负责有对应影射出来的端口进行服务,客户端connect成功之后,将一个数据包发送给路由,路由根据对应的路径发出去,路由发觉确实存在这么个端口(s3000),而且是可达的,于是就你的数据包路由出去,于是客户的send成功了.
    以上言论不具备权威性质,如有误导,请指正 
      

  6.   


    其实我觉得没有这么复杂。send只是一个编程接口而已,send只是把你的应用层数据send到socket的缓冲区里面,和你真正的协议底层没有什么关系吧。只要缓冲区有足够的大小都能send出去吧。
      

  7.   

    编程实现,服务端侦听到客户端连接,为每个客户端起一个独立线程,在线程中实现该通道下的双向通信。
    缓冲区大小,在线程中自己设置了。
    tcp/ip协议的上限是64k.
    udp协议在1500字节内。
      

  8.   

    如果你采用阻塞式发送,是可以一次发送10M文件的,操作系统会帮你分包。
    如果你采用的非阻塞,那就不行,因为非阻塞方式,你把数据提交给OS,就的调用函数就返回了,OS是需要一个缓冲区来保存你提交的数据的,而这个缓存通常就是SOCKET的发送缓存,如果你把你的SOCKET的发送缓存设置成10M的话,你也可以一次发送10M的文件。
      

  9.   

    我是楼主那大家帮我看看,我这样理解对不?
    假设A向B发送,send数据     假设应用程序自己定义的数据缓冲区是bufA,B已建立连接:
    同步情况下:
        A发送时,先从buf取数据到socket发送缓冲区,然后底层协议再发送socket里的数据到B端的socket接受缓冲区。这期间,A是一边底层发送socket缓冲区里的数据,一边从buf继续拷贝数据到socket缓冲区;
        B端接受时,也是边拷贝走B的socket接受缓冲区,边继续从A接受数据到B的socket接受缓冲区。
    -------------
        我这样理解对不?     然后,我的问题又来了!
    1:     假设在B端,socket接受缓冲区已满,但是并没有调用recv函数拷贝走socket接收缓冲区里的数据。那是不是,此时A已经无法成功发送新的数据到B端了?2: 我在做测试的时候,发一个比较大的文件,A端send速度比较快,往往B端收数据收的不完整?这个数据丢失是因为什么?在循环发送一个大文件数据时,每次循环发送之后sleep一下,就可以避免收数据不完整。但是这样效率就慢了?   请问大家,该怎样解决这个问题呢?为什么发送端发快了,就会造成数据丢失?    
      

  10.   

    在默认方式下的SOCKET,send并不意味着马上发送, 有个 nagle算法,可能是几个包一起发送
    如果接受端产生一个回应报文通知发送端没有接受空间了,发送端哪怕缓冲区已经满了,也不会启动发送,直到接受端通告发送端其已经有了接受数据的空间了。
      

  11.   

    我是楼主上面我问的都是同步发送和同步接收的问题。我想问一下,异步的情况呢?还有,异步发送的时候,应该是send后,不管发送成功与否,立即就返回了。
    那我怎么知道发送成功没有呢?
    一般采用什么方法知道呢?如果没有发送成功,是否要再次调用send直到成功?
      

  12.   

    socket一次只能发送8KB,自己分包发送保险些,socket是Windows的核心之一,具有自动性,那个想不想分包随你爱好
      

  13.   

    问题2:发送失败。在同步阻塞调用时,会在大约几分钟后返回失败;在同步非阻塞调用时,当时会发送成功,但是过几分钟底层会失败,从而导致你对该连接句柄调用任意的socket函数都会返回失败;在异步阻塞调用时,当时会返回成功,但是几分钟后会回调你的异步函数通知你连接失败。