关于判断Socket断开的问题

采用CS结构的网络应用,比如QQ,一般都有判定网络连接通断的需求,比如服务器判断客户端是否在线等。一般情况下,通过发心跳能够解决。但如果希望快速判断,那么就需要用一些特殊的方法。

走了不少弯路后,说下我现在在一个项目的server上使用的方法。

在windows平台上,最早使用的是一个客户端一个线程的方式,当然,效率就低一些了。在这种方式下,采用的是阻塞Socket,可以使用socket.sendUrgentData()方法来判定socket是否可用。如果发送时抛IOException异常,那么就是socket坏了。当然,这种方法也有其弊端,一个是必须客户端能够接受这种紧急通讯字节(需要设置一个TCP/IP选项),否则这个字节将会混在正常的数据流中。另外,依靠抛异常进行逻辑判断也并不是一个好主意。

后来server改成了Select模型,这时候,由于把socketChannel设置成了非阻塞模式,就不能用sendUrgentData了。虽然编译不会报错,但运行中不行,会抛一个java.nio.channel.IllegalBlockingModeException,这个跟网络状况无关,所以不能依靠它了。抛异常的具体原因,现在并没有弄清楚,但我感觉跟在Windows上SocketChannel的实现方法有关。那么,为了判断通断,现在是使用了InetAddress的isReachable方法。这个解决方案现在是能用,但也有些问题。因为执行isReachable时,当超时到达前是阻塞的,所以这会降低效率。另外就是在拥堵或较差的网络环境下,结果并不可靠。当然,它还会收到防火墙、路由等等设备的影响。

目前的方法是:

1、首先通过应用协议中的心跳判断客户端超时。

2、当应用逻辑判定客户端超时后,再启动一个线程进行isReachable操作。这样可以避免当客户端进行耗时操作而无法及时发送心跳导致被服务器踢掉。

用以上两条,基本可以解决问题了。美中不足的是灵敏度没那么高,必须到达超时时间,并且isReachable操作返回false后服务器才能断言客户端掉线。

还有一种方法类似于SendUrgentData,就是在Server和Client之间的通讯协议中增加一个“探测协议”,用于一端探测对方的在线情况。不过目前还没试验过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值