socket長連接的維持


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

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

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

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

import java.io.Serializable;

import java.text.SimpleDateFormat;

import java.util.Date;

 

/**

 * 維持連接的消息對象。

 * <p>

 * 創建時間:2010-7-18 上午12:22:09

 * @author HouLei

 * @since 1.0

 */

public class KeepAlive implements Serializable{

 

    private static final long serialVersionUID = -2813120366138988480L;

 

    /* 覆蓋該方法,僅用於測試使用。

     * @see java.lang.Object#toString()

     */

    @Override

    public String toString() {

        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"\t維持連接包";

    }

 

}



import java.io.IOException;

import java.io.InputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

import java.util.concurrent.ConcurrentHashMap;

 

/**

 *    C/S架構的客戶端對象,持有該對象,可以隨時向服務端發送消息。

 * <p>

 * 創建時間:2010-7-18 上午12:17:25

 * @author HouLei

 * @since 1.0

 */

public class Client {

 

    /**

     * 處理服務端發回的對象,可實現該接口。

     */

    public static interface ObjectAction{

        void doAction(Object obj,Client client);

    }

    public static final class DefaultObjectAction implements ObjectAction{

        public void doAction(Object obj,Client client) {

            System.out.println("處理:\t"+obj.toString());

        }

    }

    public static void main(String[] args) throws UnknownHostException, IOException {

        String serverIp = "127.0.0.1";

        int port = 65432;

        Client client = new Client(serverIp,port);

        client.start();

    }

     

    private String serverIp;

    private int port;

    private Socket socket;

    private boolean running=false;

    private long lastSendTime;

    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class,ObjectAction>();

     

    public Client(String serverIp, int port) {

        this.serverIp=serverIp;this.port=port;

    }

     

    public void start() throws UnknownHostException, IOException {

        if(running)return;

        socket = new Socket(serverIp,port);

        System.out.println("本地端口:"+socket.getLocalPort());

        lastSendTime=System.currentTimeMillis();

        running=true;

        new Thread(new KeepAliveWatchDog()).start();

        new Thread(new ReceiveWatchDog()).start();

    }

     

    public void stop(){

        if(running)running=false;

    }

     

    /**

     * 添加接收對象的處理對象。

     * @param cls 待處理的對象,其所屬的類。

     * @param action 處理過程對象。

     */

    public void addActionMap(Class<Object> cls,ObjectAction action){

        actionMapping.put(cls, action);

    }

 

    public void sendObject(Object obj) throws IOException {

        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

        oos.writeObject(obj);

        System.out.println("發送:\t"+obj);

        oos.flush();

    }

     

    class KeepAliveWatchDog implements Runnable{

        long checkDelay = 10;

        long keepAliveDelay = 2000;

        public void run() {

            while(running){

                if(System.currentTimeMillis()-lastSendTime>keepAliveDelay){

                    try {

                        Client.this.sendObject(new KeepAlive());

                    } catch (IOException e) {

                        e.printStackTrace();

                        Client.this.stop();

                    }

                    lastSendTime = System.currentTimeMillis();

                }else{

                    try {

                        Thread.sleep(checkDelay);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                        Client.this.stop();

                    }

                }

            }

        }

    }

     

    class ReceiveWatchDog implements Runnable{

        public void run() {

            while(running){

                try {

                    InputStream in = socket.getInputStream();

                    if(in.available()>0){

                        ObjectInputStream ois = new ObjectInputStream(in);

                        Object obj = ois.readObject();

                        System.out.println("接收:\t"+obj);

                        ObjectAction oa = actionMapping.get(obj.getClass());

                        oa = oa==null?new DefaultObjectAction():oa;

                        oa.doAction(obj, Client.this);

                    }else{

                        Thread.sleep(10);

                    }

                } catch (Exception e) {

                    e.printStackTrace();

                    Client.this.stop();

                } 

            }

        }

    }

     

}



import java.io.IOException;

import java.io.InputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.concurrent.ConcurrentHashMap;

 

/**

 * C/S架構的服務端對象。

 * <p>

 * 創建時間:2010-7-18 上午12:17:37

 * @author HouLei

 * @since 1.0

 */

public class Server {

 

    /**

     * 要處理客戶端發來的對象,並返回一個對象,可實現該接口。

     */

    public interface ObjectAction{

        Object doAction(Object rev);

    }

     

    public static final class DefaultObjectAction implements ObjectAction{

        public Object doAction(Object rev) {

            System.out.println("處理並返回:"+rev);

            return rev;

        }

    }

     

    public static void main(String[] args) {

        int port = 65432;

        Server server = new Server(port);

        server.start();

    }

     

    private int port;

    private volatile boolean running=false;

    private long receiveTimeDelay=3000;

    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class,ObjectAction>();

    private Thread connWatchDog;

     

    public Server(int port) {

        this.port = port;

    }

 

    public void start(){

        if(running)return;

        running=true;

        connWatchDog = new Thread(new ConnWatchDog());

        connWatchDog.start();

    }

     

    @SuppressWarnings("deprecation")

    public void stop(){

        if(running)running=false;

        if(connWatchDog!=null)connWatchDog.stop();

    }

     

    public void addActionMap(Class<Object> cls,ObjectAction action){

        actionMapping.put(cls, action);

    }

     

    class ConnWatchDog implements Runnable{

        public void run(){

            try {

                ServerSocket ss = new ServerSocket(port,5);

                while(running){

                    Socket s = ss.accept();

                    new Thread(new SocketAction(s)).start();

                }

            } catch (IOException e) {

                e.printStackTrace();

                Server.this.stop();

            }

             

        }

    }

     

    class SocketAction implements Runnable{

        Socket s;

        boolean run=true;

        long lastReceiveTime = System.currentTimeMillis();

        public SocketAction(Socket s) {

            this.s = s;

        }

        public void run() {

            while(running && run){

                if(System.currentTimeMillis()-lastReceiveTime>receiveTimeDelay){

                    overThis();

                }else{

                    try {

                        InputStream in = s.getInputStream();

                        if(in.available()>0){

                            ObjectInputStream ois = new ObjectInputStream(in);

                            Object obj = ois.readObject();

                            lastReceiveTime = System.currentTimeMillis();

                            System.out.println("接收:\t"+obj);

                            ObjectAction oa = actionMapping.get(obj.getClass());

                            oa = oa==null?new DefaultObjectAction():oa;

                            Object out = oa.doAction(obj);

                            if(out!=null){

                                ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

                                oos.writeObject(out);

                                oos.flush();

                            }

                        }else{

                            Thread.sleep(10);

                        }

                    } catch (Exception e) {

                        e.printStackTrace();

                        overThis();

                    } 

                }

            }

        }

         

        private void overThis() {

            if(run)run=false;

            if(s!=null){

                try {

                    s.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

            System.out.println("關閉:"+s.getRemoteSocketAddress());

        }
    }
}

 


免責聲明!

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



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