• 基于TCP协议的应用层的ACK机制


      当用TCP/IP协议进行通信时,在发送端,send首先会将数据copy到协议的缓存区,然后协议会将数据发送到接收端,接着会等待接收端协议收到数据的ack,如果没有收到ack,协议就会重发数据,在这一过程中send一直在等待,直到收到ack,当协议收到ack后才将协议缓存中的数据删除,因此从协议上来说是不会丢失数据的。

           但是协议没有丢失数据并不能保证接收端应用程序就一定会处理了数据,因此,在接收端的应用层增加ack是有必要的,因为有可能因为某些原因(比如:接收端机器配置低),应层没来得及处理数据,这也是TCP协议应用层加ack的意义所在。 

      而同样,对于在实际应用中设计应用层协议的时候,合适的ACK机制很重要。即使是基于TCP/IP的应用层,也要实现自己的ACK机制。因为TCP/IP的ACK是传输层的ACK,并不一定表示应用层已经处理了收到的消息,因为数据可能还在内核中没有被应用层读取。所以,应用层协议要有自己的ACK,进行应用层的消息确认。

      因为很多时候消息由tcp层交给应用层之后还可能出现丢失的情况,比如客户端落本地db失败了,类似这种。

      TCP属于传输层,而IM服务属于应用层,TCP的ACK只能保证传输层的可靠性,即A端到B端的可靠性,但是不能保证数据能够被应用层正确可靠处理,比如应用层里面的业务逻辑导致消息处理失败了,TCP层是不知道的。

      Tcp的ack机制可以保证通过tcp传输的数据被对端内核接受并放入对应的socket接受缓存区里面,但是接下来进程读取缓存区以及进行逻辑处理可能会出现问题,所以需要应用层的ack机制保证数据包被进程读取并正确的处理。

      每个TCP套接口有一个发送缓冲区,可以用SO_SNDBUF套接口选项来改变这一缓冲区的大小。当应用进程调用write往套接口写数据时,内核从应用进程缓冲区中拷贝所有数据到套接口的发送缓冲区,如果套接口发送缓冲区容不下应用程序的所有数据,或者是应用进程的缓冲区大于套接口的发送缓冲区,或者是套接口的发送缓冲区中有别的数据,应用进程将被挂起。内核将不从write返回。直到应用进程缓冲区中的所有数据都拷贝到套接口发送缓冲区。所以,从写一个TCP套接口的write调用成功返回仅仅表示我们可以重新使用应用进程缓冲区,它并不是告诉我们对方收到数据。TCP发给对方的数据,对方在收到数据时必须给矛确认,只有在收到对方的确认时,本方TCP才会把TCP发送缓冲区中的数据删除。

      

      -------  

      有了 TCP 协议本身的 ACK 机制为什么还需要业务层的ACK 机制?
    答:这个问题从操作系统(linux/windows/android/ios)实现TCP协议的原理角度来说明更合适: 
         1 操作系统在TCP发送端创建了一个TCP发送缓冲区,在接收端创建了一个TCP接收缓冲区;
         2 在发送端应用层程序调用send()方法成功后,实际是将数据写入了TCP发送缓冲区;
         3 根据TCP协议的规定,在TCP连接良好的情况下,TCP发送缓冲区的数据是“有序的可靠的”到达TCP接收缓冲区,然后回调接收方应用层程序来通知数据到达;
         4 但是在TCP连接断开的时候,在TCP的发送缓冲区和TCP的接收缓冲区中可能还有数据,那么操作系统如何处理呢? 
               首先,对于TCP发送缓冲区中还未发送的数据,操作系统不会通知应用层程序进行处理(试想一下:send()函数已经返回成功了,后面再告诉你失败,这样的系统如何设计?太复杂了...),通常的处理手段就是直接回收TCP发送缓存区及其socket资源;
               对于TCP接收方来说,在还未监测到TCP连接断开的时候,因为TCP接收缓冲区不再写入数据了,所以会有足够的时间进行处理,但若未来得及处理就发现了连接断开,仍然会为了及时释放资源,直接回收TCP接收缓存区和对应的socket资源。

    总结一下就是: 发送方的应用层程序,调用send()方法返回成功的时候,数据实际是写入到了TCP的发送缓冲区,而非已经被接收方的应用层程序处理。怎么办呢?只能借助于应用层的ACK机制。

  • 相关阅读:
    Tomcat中 日志(控制台)中文乱码解决方法
    Maven 编译后 内存中中文数据乱码
    .gitignore无效,不能过滤某些文件
    允许远程用户登录访问mysql的方法
    针对MySQL创建用户后无法登录的原因
    解决Eclipse每次修改完代码后需要先Clean,不然部署不上文件的问题
    Struts2与JQurey ajax配合跨域请求
    Spring 定时任务之 @Scheduled cron表达式
    颜色是这样的,so,status bar和navigation bar颜色是一致的,
    尺寸,误差,
  • 原文地址:https://www.cnblogs.com/maji233/p/11448797.html
Copyright © 2020-2023  润新知