2016-04-05 20:46:04.0|分类: netty|浏览量: 5331
客户端和服务器建立长连接之后,需要发送业务信息。由于网络不是十分稳定,连接不能保证畅通,发送消息不一定能到对方。这时候怎么办?? 一种情况服务器把消息发送出去,默认这条消息客户端一定能收到,具体客户端是否真能收到,服务器不管。显然这种处理方式不对啊!! 第二种情况服务器把消息发送出去,服务器记录这条消息的状态,客户端如果收到这条消息,向服务器发送一个回执,服务器收到这个回执将状态修改成已经收到,如果一定时间没有收到回执,则再次发送这条消息。 消息就需要重发?重发几次呢??等等一系列的问题。 服务端维护一个正在发消息的队列,服务端向客户端推送消息后,收到客户端的回执,把响应的消息从队列中移除。服务器20s之后会轮询这个消息队列,把消息队列中已经发送的消息但是没有收到回执的消息再次发送一遍。 如果同一条消息被发送了5次,一直没有收到回执,则认为服务器与客户端保持的这个长连接已经断开了,但是由于某种原因服务器没有把这个长连接关闭掉,这种情况服务器则把这个长连接对象channel关闭、释放掉资源。 如果客户端与服务器保持的长连接对象channel关闭掉,则需要处理“正在发消息的队列”对象,将属于这个链接的消息持久化到数据库中。这样做也是为了节约内容开支,都已经判断这个长连接失效了,就没有必要再次想它推送消息了。当下次再建立这个客户端的长连接的时候我们首先在数据库中查询时候有属于它的未发送消息,如果有未发送消息,则进行发送。。 服务器向客户端发送消息1次,客户端向服务器发送这条消息的回执。 服务器由于网络原因没有收到回执,这条消息的回执丢了,服务器会再把这条消息发送第二次,客户端这次会收到重复的消息,这时候客户端怎么处理呢??继续显示这条消息显然不正确,客户端需要验证这条消息是否收到,进行合法性进行验证。这里需要用到消息唯一标示。 对于上面客户端重复收到服务器推送过来的消息,魅族架构师是这么解决的,我直接引用原文相关的部分: 服务端向客户端推送一条消息的时候,正常情况下,消息推送下去,客户端到这个消息,给它回一个应答,如果回应答的过程中,服务端就收不到这个应答,服务端就有两种处理方式,一种是离线,一种是超时重试,重试几次,直到收到为止,这样服务端要保持每一条推送消息的状态,这样子如果服务端后端因为不单是一个服务组成的,是有很多服务组成的,后端的调动页就会拉得很长,每一个节点上面都需要保持状态,任何一个节点出现问题,整个都会认为这个消息是推送失败了。重复消息的话,客户端发送应答,服务端没有接到这个应答,而网络好的时候,再推送一次,那就出现重复了。 那怎么解决这个问题?设置了消息基于序列号的交互方式,首先推送消息的时候,不是把消息直接推送下去,是发一个通知到客户端,告诉你有消息,客户端拿到这个通知,发送一个指令上来,说获取这个消息,会带上一个收到最近消息的最大的序列号。这里有一个大坑,也就是DNS也容易出现问题,相信很多人都碰到过这样的情况。怎么解决这个问题?用全IP的方式,要接入服务器的话,我们这边有一个WEBService,里面有很多的IP列表,IP列表都拉下来,客户端直接选取一个IP地址直接去连接,看下面第一个图的第一步,通过HTTP访问客户端的,但是也存在一个域名的问题,我们做了预埋,直接用DNS访问,如果这个DNS访问不通,就可以用预埋的IP来访问,就可以拿到一个IP地址。 客户端同样也存在消息重发过程,这里我们就不详细说了,如果充分时间,会再补充~~ |