目前为了判断客户端是否掉线,我使用的方案是:客户端每秒发送心跳信息,服务器端起一Timer 线程每10s去判读,如果三次都未读到心跳信息,则判断客户端已经掉线,则将该socket 关闭,另外我的通信基于外网环境,在通信中为防止丢包现象,我又使用的方案是:服务器发送聊天信息给客户端,客户端收到信息后反馈接收到的回馈,若服务器端未收到回馈信息则重复发送,三次未收到信息则确定该客户端也已掉线。我的问题是如何由于两种实现都在服务器端线程使用到了readLine()去接收信息,我如何区分是心跳信息还是正常接收到信息后反馈信息,因为同时使用readLine()的话会导致两个阻塞线程去接收信息。各位对这种处理有什么好的建议吗?

解决方案 »

  1.   

    我做的话会使用不用的标志去区分不同种类的信息,比如在每条信息的头部添加一个标志(如字符串“flag1”),这个标志必须是可区分的。
      

  2.   

    你每条消息要有包头的吧,包头里面放进消息的类型,
    最好只有一个线程readline(),然后判断消息类型进行分发处理
    String s=io.readline();
    if(s.startwith("a")){
    //一种消息类型
    }else if(s.startwith("b")){
    //另一种消息类型
    }
    心跳不一定靠心跳命令来维持,正常的包过来,应该也算一个心跳包。
      

  3.   

    若是发送数据包过去肯定会和应用数据包混淆,服务器端实现较复杂
    曾经看到一种方法,没试过是否可行,LZ可以试试起个线程后,每个一段时间调用socket的sendUrgentData方法,若没有异常,则表示连接是好的,这个方法的好处就是服务器端不会收到客户端的数据,这个前提是禁用OOBINLINE,默认情况下,此选项是禁用的!
      

  4.   

    涉及到阻滞问题,所以建议用NIO的方式实现,
    心跳信息加个标示位就好,类似楼上的。开始我也用自己完全实现了NIO。瞬间发送上千数据也基本没有丢失。
    后面要用Socket传递文件的时候,自己分包装包。最后虽然实现了。但是感觉速度不够。现在我用mina框架。传递文件交给FTP。判断断线有3个,一个是每个连接存在的时候,都放在一个内存里面hashma,value是sesion。然后有个定时器,每n分钟去检查,断了就关闭服务器。
    另外还有一个mina提供的sessionIdle,就是一定时间没有受到信息的话,就断开。
    第三个自然是客户端主动要求断开的。这样的做法,服务器端一起就2个线程,一个server,一个是定时器的。
    没有多线程,性能大大提高。你这样单独的time去检查超时,如果连接大了,容易丢失,速度也不够
      

  5.   

    心跳包检查最好是发送带外数据来实现,千万别真发数据过去
    建议你读一下TCP的RFC协议关于带外数据
      

  6.   


    感觉需要反馈的吧,不然丢包了,那么服务器就强断了。应该返回表示收到。比如paypal收费,都是要交互2次确定不丢失
      

  7.   

    心跳是不需要反馈的,为了节约性能一般使用udp由客户端向服务器发包。
      

  8.   

    1.客户端发送心跳信息你只需接收下吧,那个心跳信息用个特殊标识就行啊
    2.至于防止通信中丢包现象,udp的话,应该用stop-and-wait方法去做,即先将要发的包排好序,然后先发一批出去,等待响应,收到后再发一批,至于响应,我觉得客户端返回一个标识即可,而tcp的话,实在不明白为什么要防止丢包,要出现丢包,那是网络问题,是物理层或者网关的问题了,你程序不必关心和解决吧。
    3.防阻塞的话用nio吧
    4.建议用mina2
      

  9.   

    心跳保活机制正常情况下是这样实现的:服务器定时给客户端发消息,若长时间没有收到客户端的回复则认为客户端断开了,此时服务器应关掉相对应的连接,释放资源。反之,若客户端长时间没有收到服务器的保活消息,则认为服务器断开了。
    java Socket实现心跳保活非常容易,因为java有异常机制。我们可以在服务器端启动一个定时器(Timer类),不停给客户端发消息,如果客户端断开了则服务器会出现异常(IOException等),所以可以根据异常信息判断客户端断开了。同理客户端在接收保活消息时出了相应异常,则断然认为服务器断开了,此时可以关掉socket实例!
    谢谢,望高人点评!
      

  10.   

    自定义数据包格式比较靠谱!
    这个其实很简单的,使用ObjectOutputStream和ObjectInputStream就可以了,你自定义一个类型,或者干脆就用一个MAP,作为消息的封装工具!
    你随便定义一些可被忽略的数据包,比如MSGID==Constant.NULL诸如此类的,你的客户端时不时地发一些这样的垃圾包到服务器,服务器根本不用启动线程,就设置一个读取超时,当超过多少时间没有读到数据包就把它干掉!