[转]tcp不能保证数据传输的万无一失

[转]tcp不能保证数据传输的万无一失

  ■tcp认识的误区


  应用开发人员常常遇到这样的困惑:为什么用tcp写的应用还会出现数据丢失呢?很多人都以为tcp 协议可以确保数据的传输,但事实上没有任何一种协议可以做到这一点。tcp所能做只是传输数据,如果失败了,它会通知你,但它无法告诉你有多少数据没有被正确传送。

  tcp 协议中的应答机制使得发送方的tcp栈确保接收方tcp栈收到了数据。

  tcp包头包括32位的顺序码和应答码,顺序码是在连接建立时随机产生的,并随着传输的字节数递增。当数据被接收时,接收方的tcp栈会给发送方发送应答码, 如果发送方没收到应答码, 它就会重发该数据。发方和收方的顺序码是各自独立的。


  ■tcp是一个窗口式的协议


  tcp是一个窗口式的协议。tcp包头数据中也包含窗口的大小,它告诉远端再传多少数据后就必须停止。窗口大小实际上就是缓存区的大小,当缓冲区满的 时候,窗口就会关闭。当发送方收到的应答中窗口大小为零时,它会自动停止发送。发送方会记住自己发送了多少数据,即使没有收到窗口大小为零的应答,它也不 会发送大于缓冲区的数据。

  通常接收方应答这些数据时,应用会不断读数据,这样窗口就经常处于开放状态。

  导致窗口关闭的最常见原因是i/o阻塞。这通常是临时性的,一般i/o通畅后,缓存(窗口)会自动开放。第二个原因就是应用代码中的bug使得接收应用程序忽略了连接,重要的不在于接收方读没读数据,而在于发送方在收到应答后是否正确地发送了数据。


  ■tcp的缓存机制


  发送tcp栈在收到应答前必须对数据进行缓存,而应用程序在调用tcp栈发送数据时并不知道数据已经在缓存区了。只要发送tcp栈还有空间,它就会接收来自应用的数据并进行缓存。一旦缓存满了导致应用程序无法继续发送,它就会认为有问题了。

  如果问题是发送tcp栈没有收到应答,那么它会重发,等待应答的时间会越来越长,直至最终放弃并重新建立连接。重新连接后本地缓存会清空,并通知应用 程序。但是至于有多少数据在缓存区没有收到应答仍不得而知。本地tcp栈无法知道远端是否收到了数据,也不知道是否收到了远端应答。

  如果问题是窗口关闭了,那么发送tcp栈会定期发送窗口探针来探测接收方窗口是否开放。接收tcp栈必须应答窗口探针包。应答包含当前窗口大小。在收到探针应答前,发送tcp栈只能等待。


  ■路在何方


  也许有人会说:既然如此,为何还要用tcp协议?如果应用中必须包括数据标识和应答,为什么不用udp协议?tcp的优势在于你不必担心数据传输机 制,如果数据包在传输过程中由于路由的关系,其到达顺序被打乱,接收tcp栈会将这些数据包按其顺序码重新排列,从而保证了数据的正确性。而如果采用 udp的话,则应用中必须设法提供所有这些机制。

  如果发生了传输线路中断,仅有应用层的应答是不够的。按照应用层应答机制,在重建连接后,发送方会重发那些没有收到应答的数据包,但是有可能虽然这些 应答丢了,可数据却到达了,并已用于应用程序。为了防止这种情况,发送应用方需保存没被接收应用应答的数据段的标识 ,接收应用方也应保存自己已接收和处理过的数据段的标识。当重建连接时,发送方将发送第一个没有收到应答的数据段,或者询问接收方最后发出的应答进行确 认。为了确保数据传输的无误, 应该保证接收应用方保存的数据段标识在应用重启或系统瘫痪时仍能安然无恙。

  尽管tcp协议十分优秀,但它并不能确保数据数据传输万无一失。

你可能感兴趣的:([转]tcp不能保证数据传输的万无一失)