按这样组网: A机器 <----> 交换机1 <----> 交换机2 <----> B机器,A、B机器上各一个进程,相互之间socket使用TCP方式传送消息。
有个需求是,当A机器数据变更后,需要发送一个广播通知消息至B机器(消息包比较大,几十K甚至1M以上)。但是有这样一种情况,就是如果 A机器正要 send 数据时,如果此时交换机之间的链路断了,由于 A、B机器都检测不到这个断链,因此 A机器调用 send 肯定是返回成功的。如果交换机之间的链路立即就恢复了(瞬断),那还好,TCP会将此数据正常传输至B机器;但是如果交换机之间的链路较长时间不恢复的话(例如1分钟左右),那就麻烦了,B机器将可能就收不到这个消息了,导致部分处理异常。
我查询了一下TCP传输的相关资料,TCP在传输数据时,为保证数据正确性,都有个包发送和确认(ACK)机制,如果发送数据后在重发超时到来之前都未收到确认信息,那么就会重发包,但是如果数次重发都未收到应答,就会直接将这个包丢弃。我的这个情况应该就是由于中间链路断得过久,导致包被丢弃了。
我想如果能够实现这么一个机制,既如果A机器发送数据后,如果发现包被丢弃的情况,那么就再重发,一直尝试发送成功为止,这样就能极大的避免通知丢失的问题。但是问题是:
1、如何判断本次发送的包丢失了?
2、怎样判断包正常的发送到了B机器(不能期望B机器应答消息,因为这个是通知,而且那个是另外一个公司开发的程序,无法修改)

解决方案 »

  1.   

    TCP自身就有发送数据验证功能,send函数的返回值>0就说明另一端已经收到数据。
    象你的这种情况如果send的返回值<1,就重新建立连接发送数据。
     
      

  2.   

    我也很好奇,TCP也能广播,而且广播的消息是能高于1M?
      

  3.   


    如果真是这样,TCP不会有重发功能了。send()返回成功,只代表你要发送的数据被成功复制到系统winsock缓冲(也就是AFD.SYS本身的内部缓冲),并不代表你的数据成功发送给对方,对方并且成功接收到.至于后面的事情,就是系统本身在处理,如果发送失败,系统会再重发这些数据,但在应用层,你并不知道内核到底有没有重发或者重发是否也失败。虽然出现的机率很低,但TCP一样会出现发包失败的情况,而且应用层程序并不知晓失败了。
      

  4.   

    有一种简单的笨方法应该能解决这个问题,如果真是TCP传输的话。先放几天,让其他人发表下意见,还没解决我再将方法发出来,我自己也先做个测试证实下。
      

  5.   

    貌似不是这样的,只要数据拷贝到系统的缓存区,send函数就会返回。
      

  6.   

    楼主这个要求根本就达不到,因为,Windows系统自身都不知道对方是否已经接收到数据。整个网络系统(Socket)在设计的时候,并没有这样设计。
      

  7.   

    广播是应用程序自行开发的,广播消息在底层是用TCP发送的而已。
      

  8.   


    我等得心痒痒了,可否提示一下,因为老板催得急啊,呵呵。
    因为当TCP发送失败导致丢包时,会自行产生一个 网络不可达(或端口不可达) 的ICMP消息,因此我有一个想法,就是发送数据后,先将发送消息缓存起来,然后设置一个超时时间(例如3分钟),如果在超时时间之内,收到ICMP的不可达消息,就重发事先缓存的消息,一直重复上述过程,直到在超时时间内都未收到ICMP不可达消息,就认为对方已经收到了,再将缓存的消息删除。
    但是这样做的话,对于广播风暴的情况,可能导致进程中为缓存消息花费太大的内存,这样可能会导致程序内存耗尽而崩溃。所以不敢轻易采用此方法。
      

  9.   


    提示: 让接收方发送ACK确认包后,发送方的应用程序的send()才返回成功结果。
      

  10.   

    tcp的重发机制保证了你这包未达到,你的socket不会recv出来下一包的,虽然它有可能已经在内核的缓冲区里,底层给做好序列化了。还有,不要自己再做每包的应答了,那样还用tcp干啥,接收端记录下收到哪里了就好了,需要重传的时候就告诉发送端从那开始发就行了。
      

  11.   

    就像14L说的 要接收到ACK 因为只有收到ACK才能一定确定B收到包 没有别的办法了但是怎么把传输层的ACK和应用层的东西联系起来呢..期待..
      

  12.   

    是啊,期待 WinEggDrop 给出个例子程序,看看如何分析 ack 包,另外怎么知道发送的包的流水号呢?用原始套接字吗?
      

  13.   

    WinEggDrop,可否发个实例上来看看?
      

  14.   

    如果对方没有应答,TCP发送方不会丢弃报文,会一直等下去直到连接状态发生变化(请参考TCP状态转移图),
    1ms,2ms,4ms,8ms,16ms等待重传一般以这种方式增涨
    继续发送会导致发缓冲区溢出,可以在Send函数通过WSAGetLastError获得错误类型WSAENOBUFS还有一种情况就是你的等待时间已经超过了所能容忍的范围,会导致Tcp Socket错误,这个等待时间应该是个可配置的参数可以查找相关资料。
      

  15.   

    说得对,包真正有没有获得,只有B知道,B只要记录下接受的情况,如果没有接收到,就告诉A给我重发某某段,这个应当是客户端来承担起容错的工作。