关于java socket 心跳处理方案

colin_fantasy 2010-03-09 10:22:24
目前为了判断客户端是否掉线,我使用的方案是:客户端每秒发送心跳信息,服务器端起一Timer 线程每10s去判读,如果三次都未读到心跳信息,则判断客户端已经掉线,则将该socket 关闭,另外我的通信基于外网环境,在通信中为防止丢包现象,我又使用的方案是:服务器发送聊天信息给客户端,客户端收到信息后反馈接收到的回馈,若服务器端未收到回馈信息则重复发送,三次未收到信息则确定该客户端也已掉线。我的问题是如何由于两种实现都在服务器端线程使用到了readLine()去接收信息,我如何区分是心跳信息还是正常接收到信息后反馈信息,因为同时使用readLine()的话会导致两个阻塞线程去接收信息。各位对这种处理有什么好的建议吗?
...全文
4202 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
Jason-Gao 2012-10-23
  • 打赏
  • 举报
回复
没挖到,继续挖。。。。 求解决方案
zoeg 2012-10-23
  • 打赏
  • 举报
回复
自定义数据包格式比较靠谱!
这个其实很简单的,使用ObjectOutputStream和ObjectInputStream就可以了,你自定义一个类型,或者干脆就用一个MAP,作为消息的封装工具!
你随便定义一些可被忽略的数据包,比如MSGID==Constant.NULL诸如此类的,你的客户端时不时地发一些这样的垃圾包到服务器,服务器根本不用启动线程,就设置一个读取超时,当超过多少时间没有读到数据包就把它干掉!
Kanepan 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

若是发送数据包过去肯定会和应用数据包混淆,服务器端实现较复杂


曾经看到一种方法,没试过是否可行,LZ可以试试

起个线程后,每个一段时间调用socket的sendUrgentData方法,若没有异常,则表示连接是好的,这个方法的好处就是服务器端不会收到客户端的数据,这个前提是禁用OOBINLINE,默认情况下,此选项是禁用的!
[/Quote]

理论上可行,跟您一样没实际在生产上应用过。
想喝咖啡的貓 2011-09-23
  • 打赏
  • 举报
回复
挖坟,求已实现的,给个解决方案。
angelfly7 2011-07-20
  • 打赏
  • 举报
回复
目前正在做个,原理想的通,代码不知道怎么写,
wstxdz1023 2011-07-20
  • 打赏
  • 举报
回复
目前正在做个,原理想的通,代码不知道怎么写,
muamomo 2011-07-06
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 yuwenbao 的回复:]
1.客户端发送心跳信息你只需接收下吧,那个心跳信息用个特殊标识就行啊
2.至于防止通信中丢包现象,udp的话,应该用stop-and-wait方法去做,即先将要发的包排好序,然后先发一批出去,等待响应,收到后再发一批,至于响应,我觉得客户端返回一个标识即可,而tcp的话,实在不明白为什么要防止丢包,要出现丢包,那是网络问题,是物理层或者网关的问题了,你程序不必关心和解决吧。
3.防阻塞的话用n……
[/Quote]
重点
wangxuhexiyuan 2011-06-29
  • 打赏
  • 举报
回复
心跳保活机制正常情况下是这样实现的:服务器定时给客户端发消息,若长时间没有收到客户端的回复则认为客户端断开了,此时服务器应关掉相对应的连接,释放资源。反之,若客户端长时间没有收到服务器的保活消息,则认为服务器断开了。
java Socket实现心跳保活非常容易,因为java有异常机制。我们可以在服务器端启动一个定时器(Timer类),不停给客户端发消息,如果客户端断开了则服务器会出现异常(IOException等),所以可以根据异常信息判断客户端断开了。同理客户端在接收保活消息时出了相应异常,则断然认为服务器断开了,此时可以关掉socket实例!
谢谢,望高人点评!
kurama_mail 2010-06-09
  • 打赏
  • 举报
回复
心跳是不需要反馈的,为了节约性能一般使用udp由客户端向服务器发包。
SDMRauquin 2010-06-09
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 java2000_net 的回复:]

心跳是单向的,你无需向客户端反馈什么!
[/Quote]

感觉需要反馈的吧,不然丢包了,那么服务器就强断了。应该返回表示收到。

比如paypal收费,都是要交互2次确定不丢失
izard999 2010-06-09
  • 打赏
  • 举报
回复
留个名,学习下
老紫竹 2010-06-09
  • 打赏
  • 举报
回复
心跳是单向的,你无需向客户端反馈什么!
gloomyfish 2010-06-09
  • 打赏
  • 举报
回复
心跳包检查最好是发送带外数据来实现,千万别真发数据过去
建议你读一下TCP的RFC协议关于带外数据
SDMRauquin 2010-06-09
  • 打赏
  • 举报
回复
涉及到阻滞问题,所以建议用NIO的方式实现,
心跳信息加个标示位就好,类似楼上的。

开始我也用自己完全实现了NIO。瞬间发送上千数据也基本没有丢失。
后面要用Socket传递文件的时候,自己分包装包。最后虽然实现了。但是感觉速度不够。

现在我用mina框架。传递文件交给FTP。

判断断线有3个,一个是每个连接存在的时候,都放在一个内存里面hashma,value是sesion。然后有个定时器,每n分钟去检查,断了就关闭服务器。
另外还有一个mina提供的sessionIdle,就是一定时间没有受到信息的话,就断开。
第三个自然是客户端主动要求断开的。

这样的做法,服务器端一起就2个线程,一个server,一个是定时器的。
没有多线程,性能大大提高。

你这样单独的time去检查超时,如果连接大了,容易丢失,速度也不够
dr_lou 2010-06-09
  • 打赏
  • 举报
回复
通过包头做判断呗。自定义包的格式。
mochibing 2010-06-09
  • 打赏
  • 举报
回复
如果条件允许的话在服务端接受心跳信息和反馈信息的端口分开,两个侦听程序各做各的互不干扰
龙四 2010-06-09
  • 打赏
  • 举报
回复
若是发送数据包过去肯定会和应用数据包混淆,服务器端实现较复杂


曾经看到一种方法,没试过是否可行,LZ可以试试

起个线程后,每个一段时间调用socket的sendUrgentData方法,若没有异常,则表示连接是好的,这个方法的好处就是服务器端不会收到客户端的数据,这个前提是禁用OOBINLINE,默认情况下,此选项是禁用的!
俊哥123 2010-06-09
  • 打赏
  • 举报
回复
你每条消息要有包头的吧,包头里面放进消息的类型,
最好只有一个线程readline(),然后判断消息类型进行分发处理
String s=io.readline();
if(s.startwith("a")){
//一种消息类型
}else if(s.startwith("b")){
//另一种消息类型
}
。。。

心跳不一定靠心跳命令来维持,正常的包过来,应该也算一个心跳包。
黎某人 2010-06-09
  • 打赏
  • 举报
回复
一般客户端掉线 服务器会有异常捕获 你在异常里处理就好了吧 关于网络延迟厉害什么的,在客户端验证就好了
yuwenbao 2010-06-09
  • 打赏
  • 举报
回复
1.客户端发送心跳信息你只需接收下吧,那个心跳信息用个特殊标识就行啊
2.至于防止通信中丢包现象,udp的话,应该用stop-and-wait方法去做,即先将要发的包排好序,然后先发一批出去,等待响应,收到后再发一批,至于响应,我觉得客户端返回一个标识即可,而tcp的话,实在不明白为什么要防止丢包,要出现丢包,那是网络问题,是物理层或者网关的问题了,你程序不必关心和解决吧。
3.防阻塞的话用nio吧
4.建议用mina2
加载更多回复(3)

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧