JAVA實現長連接(含心跳檢測)Demo


實現原理:

       長連接的維持,是要客戶端程序,定時向服務端程序,發送一個維持連接包的。
       如果,長時間未發送維持連接包,服務端程序將斷開連接。

客戶端:
       Client通過持有Socket的對象,可以隨時(使用sendObject方法)發送Massage Object(消息)給服務端。
       如果keepAliveDelay毫秒(程序中是2秒)內未發送任何數據,則自動發送一個KeepAlive Object(心跳)給服務端,用於維持連接。
       由於,我們向服務端,可以發送很多不同的消息對象,服務端也可以返回不同的對象。所以,對於返回對象的處理,要編寫具體的ObjectAction實現類進行處理。通過Client.addActionMap方法進行添加。這樣,程序會回調處理。

服務端:
        由於客戶端會定時(keepAliveDelay毫秒)發送維持連接的信息過來,所以,服務端要有一個檢測機制。
        即當服務端receiveTimeDelay毫秒(程序中是3秒)內未接收任何數據,則自動斷開與客戶端的連接。
         ActionMapping的原理與客戶端相似(相同)。

         通過添加相應的ObjectAction實現類,可以實現不同對象的響應、應答過程。

心跳反映的代碼:

復制代碼
**
 * 
 * 維持連接的消息對象(心跳對象)
 */
public class KeepAlive implements Serializable{
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> <span style="color: #0000ff">long</span> serialVersionUID = -2813120366138988480L<span style="color: #000000">;

</span><span style="color: #008000">/*</span><span style="color: #008000"> 覆蓋該方法,僅用於測試使用。
 * @see java.lang.Object#toString()
 </span><span style="color: #008000">*/</span><span style="color: #000000">
@Override
</span><span style="color: #0000ff">public</span><span style="color: #000000"> String toString() {
    </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(<span style="color: #0000ff">new</span> Date())+"\t維持連接包"<span style="color: #000000">;
}

}

復制代碼

客戶端的代碼:

復制代碼
public class Client {
</span><span style="color: #008000">/**</span><span style="color: #008000">
 * 處理服務端發回的對象,可實現該接口。
 </span><span style="color: #008000">*/</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">interface</span><span style="color: #000000"> ObjectAction{
    </span><span style="color: #0000ff">void</span><span style="color: #000000"> doAction(Object obj,Client client);
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> <span style="color: #0000ff">class</span> DefaultObjectAction <span style="color: #0000ff">implements</span><span style="color: #000000"> ObjectAction{
    </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> doAction(Object obj,Client client) {
        System.out.println(</span>"處理:\t"+<span style="color: #000000">obj.toString());
    }
}


</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> main(String[] args) <span style="color: #0000ff">throws</span><span style="color: #000000"> UnknownHostException, IOException {
    String serverIp </span>= "127.0.0.1"<span style="color: #000000">;
    </span><span style="color: #0000ff">int</span> port = 65432<span style="color: #000000">;
    Client client </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> Client(serverIp,port);
    client.start();
}

</span><span style="color: #0000ff">private</span><span style="color: #000000"> String serverIp;
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">int</span><span style="color: #000000"> port;
</span><span style="color: #0000ff">private</span><span style="color: #000000"> Socket socket;
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">boolean</span> running=<span style="color: #0000ff">false</span>; <span style="color: #008000">//</span><span style="color: #008000">連接狀態</span>

<span style="color: #0000ff">private</span> <span style="color: #0000ff">long</span> lastSendTime; <span style="color: #008000">//</span><span style="color: #008000">最后一次發送數據的時間

</span><span style="color: #008000">//</span><span style="color: #008000">用於保存接收消息對象類型及該類型消息處理的對象</span>
<span style="color: #0000ff">private</span> ConcurrentHashMap&lt;Class, ObjectAction&gt; actionMapping = <span style="color: #0000ff">new</span> ConcurrentHashMap&lt;Class,ObjectAction&gt;<span style="color: #000000">();

</span><span style="color: #0000ff">public</span> Client(String serverIp, <span style="color: #0000ff">int</span><span style="color: #000000"> port) {
    </span><span style="color: #0000ff">this</span>.serverIp=<span style="color: #000000">serverIp;
    </span><span style="color: #0000ff">this</span>.port=<span style="color: #000000">port;
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> start() <span style="color: #0000ff">throws</span><span style="color: #000000"> UnknownHostException, IOException {
    </span><span style="color: #0000ff">if</span>(running)<span style="color: #0000ff">return</span><span style="color: #000000">;
    socket </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> Socket(serverIp,port);
    System.out.println(</span>"本地端口:"+<span style="color: #000000">socket.getLocalPort());
    lastSendTime</span>=<span style="color: #000000">System.currentTimeMillis();
    running</span>=<span style="color: #0000ff">true</span><span style="color: #000000">;
    </span><span style="color: #0000ff">new</span> Thread(<span style="color: #0000ff">new</span> KeepAliveWatchDog()).start();  <span style="color: #008000">//</span><span style="color: #008000">保持長連接的線程,每隔2秒項服務器發一個一個保持連接的心跳消息</span>
    <span style="color: #0000ff">new</span> Thread(<span style="color: #0000ff">new</span> ReceiveWatchDog()).start();    <span style="color: #008000">//</span><span style="color: #008000">接受消息的線程,處理消息</span>

}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> stop(){
    </span><span style="color: #0000ff">if</span>(running)running=<span style="color: #0000ff">false</span><span style="color: #000000">;
}

</span><span style="color: #008000">/**</span><span style="color: #008000">
 * 添加接收對象的處理對象。
 * </span><span style="color: #808080">@param</span><span style="color: #008000"> cls 待處理的對象,其所屬的類。
 * </span><span style="color: #808080">@param</span><span style="color: #008000"> action 處理過程對象。
 </span><span style="color: #008000">*/</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> addActionMap(Class&lt;Object&gt;<span style="color: #000000"> cls,ObjectAction action){
    actionMapping.put(cls, action);
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> sendObject(Object obj) <span style="color: #0000ff">throws</span><span style="color: #000000"> IOException {
    ObjectOutputStream oos </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ObjectOutputStream(socket.getOutputStream());
    oos.writeObject(obj);
    System.out.println(</span>"發送:\t"+<span style="color: #000000">obj);
    oos.flush();
}

</span><span style="color: #0000ff">class</span> KeepAliveWatchDog <span style="color: #0000ff">implements</span><span style="color: #000000"> Runnable{
    </span><span style="color: #0000ff">long</span> checkDelay = 10<span style="color: #000000">;
    </span><span style="color: #0000ff">long</span> keepAliveDelay = 2000<span style="color: #000000">;
    </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() {
        </span><span style="color: #0000ff">while</span><span style="color: #000000">(running){
            </span><span style="color: #0000ff">if</span>(System.currentTimeMillis()-lastSendTime&gt;<span style="color: #000000">keepAliveDelay){
                </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
                    Client.</span><span style="color: #0000ff">this</span>.sendObject(<span style="color: #0000ff">new</span><span style="color: #000000"> KeepAlive());
                } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (IOException e) {
                    e.printStackTrace();
                    Client.</span><span style="color: #0000ff">this</span><span style="color: #000000">.stop();
                }
                lastSendTime </span>=<span style="color: #000000"> System.currentTimeMillis();
            }</span><span style="color: #0000ff">else</span><span style="color: #000000">{
                </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
                    Thread.sleep(checkDelay);
                } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (InterruptedException e) {
                    e.printStackTrace();
                    Client.</span><span style="color: #0000ff">this</span><span style="color: #000000">.stop();
                }
            }
        }
    }
}

</span><span style="color: #0000ff">class</span> ReceiveWatchDog <span style="color: #0000ff">implements</span><span style="color: #000000"> Runnable{
    </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() {
        </span><span style="color: #0000ff">while</span><span style="color: #000000">(running){
            </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
                InputStream in </span>=<span style="color: #000000"> socket.getInputStream();
                </span><span style="color: #0000ff">if</span>(in.available()&gt;0<span style="color: #000000">){
                    ObjectInputStream ois </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ObjectInputStream(in);
                    Object obj </span>=<span style="color: #000000"> ois.readObject();
                    System.out.println(</span>"接收:\t"+<span style="color: #000000">obj);
                    ObjectAction oa </span>=<span style="color: #000000"> actionMapping.get(obj.getClass());
                    oa </span>= oa==<span style="color: #0000ff">null</span>?<span style="color: #0000ff">new</span><span style="color: #000000"> DefaultObjectAction():oa;
                    oa.doAction(obj, Client.</span><span style="color: #0000ff">this</span><span style="color: #000000">);
                }</span><span style="color: #0000ff">else</span><span style="color: #000000">{
                    Thread.sleep(</span>10<span style="color: #000000">);
                }
            } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (Exception e) {
                e.printStackTrace();
                Client.</span><span style="color: #0000ff">this</span><span style="color: #000000">.stop();
            } 
        }
    }
}

}

復制代碼

服務短的代碼:

復制代碼
public class Server {
</span><span style="color: #008000">/**</span><span style="color: #008000">
 * 要處理客戶端發來的對象,並返回一個對象,可實現該接口。
 </span><span style="color: #008000">*/</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span><span style="color: #000000"> ObjectAction{
    Object doAction(Object rev, Server server);
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> <span style="color: #0000ff">class</span> DefaultObjectAction <span style="color: #0000ff">implements</span><span style="color: #000000"> ObjectAction{
    </span><span style="color: #0000ff">public</span><span style="color: #000000"> Object doAction(Object rev,Server server) {
        System.out.println(</span>"處理並返回:"+<span style="color: #000000">rev);
        </span><span style="color: #0000ff">return</span><span style="color: #000000"> rev;
    }
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) {
    </span><span style="color: #0000ff">int</span> port = 65432<span style="color: #000000">;
    Server server </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> Server(port);
    server.start();
}

</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">int</span><span style="color: #000000"> port;
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">volatile</span> <span style="color: #0000ff">boolean</span> running=<span style="color: #0000ff">false</span><span style="color: #000000">;
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">long</span> receiveTimeDelay=3000<span style="color: #000000">;
</span><span style="color: #0000ff">private</span> ConcurrentHashMap&lt;Class, ObjectAction&gt; actionMapping = <span style="color: #0000ff">new</span> ConcurrentHashMap&lt;Class,ObjectAction&gt;<span style="color: #000000">();
</span><span style="color: #0000ff">private</span><span style="color: #000000"> Thread connWatchDog;

</span><span style="color: #0000ff">public</span> Server(<span style="color: #0000ff">int</span><span style="color: #000000"> port) {
    </span><span style="color: #0000ff">this</span>.port =<span style="color: #000000"> port;
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> start(){
    </span><span style="color: #0000ff">if</span>(running)<span style="color: #0000ff">return</span><span style="color: #000000">;
    running</span>=<span style="color: #0000ff">true</span><span style="color: #000000">;
    connWatchDog </span>= <span style="color: #0000ff">new</span> Thread(<span style="color: #0000ff">new</span><span style="color: #000000"> ConnWatchDog());
    connWatchDog.start();
}

@SuppressWarnings(</span>"deprecation"<span style="color: #000000">)
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> stop(){
    </span><span style="color: #0000ff">if</span>(running)running=<span style="color: #0000ff">false</span><span style="color: #000000">;
    </span><span style="color: #0000ff">if</span>(connWatchDog!=<span style="color: #0000ff">null</span><span style="color: #000000">)connWatchDog.stop();
}

</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> addActionMap(Class&lt;Object&gt;<span style="color: #000000"> cls,ObjectAction action){
    actionMapping.put(cls, action);
}

</span><span style="color: #0000ff">class</span> ConnWatchDog <span style="color: #0000ff">implements</span><span style="color: #000000"> Runnable{
    </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run(){
        </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
            ServerSocket ss </span>= <span style="color: #0000ff">new</span> ServerSocket(port,5<span style="color: #000000">);
            </span><span style="color: #0000ff">while</span><span style="color: #000000">(running){
                Socket s </span>=<span style="color: #000000"> ss.accept();
                </span><span style="color: #0000ff">new</span> Thread(<span style="color: #0000ff">new</span><span style="color: #000000"> SocketAction(s)).start();
            }
        } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (IOException e) {
            e.printStackTrace();
            Server.</span><span style="color: #0000ff">this</span><span style="color: #000000">.stop();
        }
        
    }
}

</span><span style="color: #0000ff">class</span> SocketAction <span style="color: #0000ff">implements</span><span style="color: #000000"> Runnable{
    Socket s;
    </span><span style="color: #0000ff">boolean</span> run=<span style="color: #0000ff">true</span><span style="color: #000000">;
    </span><span style="color: #0000ff">long</span> lastReceiveTime =<span style="color: #000000"> System.currentTimeMillis();
    </span><span style="color: #0000ff">public</span><span style="color: #000000"> SocketAction(Socket s) {
        </span><span style="color: #0000ff">this</span>.s =<span style="color: #000000"> s;
    }
    </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() {
        </span><span style="color: #0000ff">while</span>(running &amp;&amp;<span style="color: #000000"> run){
            </span><span style="color: #0000ff">if</span>(System.currentTimeMillis()-lastReceiveTime&gt;<span style="color: #000000">receiveTimeDelay){
                overThis();
            }</span><span style="color: #0000ff">else</span><span style="color: #000000">{
                </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
                    InputStream in </span>=<span style="color: #000000"> s.getInputStream();
                    </span><span style="color: #0000ff">if</span>(in.available()&gt;0<span style="color: #000000">){
                        ObjectInputStream ois </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ObjectInputStream(in);
                        Object obj </span>=<span style="color: #000000"> ois.readObject();
                        lastReceiveTime </span>=<span style="color: #000000"> System.currentTimeMillis();
                        System.out.println(</span>"接收:\t"+<span style="color: #000000">obj);
                        ObjectAction oa </span>=<span style="color: #000000"> actionMapping.get(obj.getClass());
                        oa </span>= oa==<span style="color: #0000ff">null</span>?<span style="color: #0000ff">new</span><span style="color: #000000"> DefaultObjectAction():oa;
                        Object out </span>= oa.doAction(obj,Server.<span style="color: #0000ff">this</span><span style="color: #000000">);
                        </span><span style="color: #0000ff">if</span>(out!=<span style="color: #0000ff">null</span><span style="color: #000000">){
                            ObjectOutputStream oos </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ObjectOutputStream(s.getOutputStream());
                            oos.writeObject(out);
                            oos.flush();
                        }
                    }</span><span style="color: #0000ff">else</span><span style="color: #000000">{
                        Thread.sleep(</span>10<span style="color: #000000">);
                    }
                } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (Exception e) {
                    e.printStackTrace();
                    overThis();
                } 
            }
        }
    }
    
    </span><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span><span style="color: #000000"> overThis() {
        </span><span style="color: #0000ff">if</span>(run)run=<span style="color: #0000ff">false</span><span style="color: #000000">;
        </span><span style="color: #0000ff">if</span>(s!=<span style="color: #0000ff">null</span><span style="color: #000000">){
            </span><span style="color: #0000ff">try</span><span style="color: #000000"> {
                s.close();
            } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(</span>"關閉:"+<span style="color: #000000">s.getRemoteSocketAddress());
    }
    
}

}

復制代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM