长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。
如果,长时间未发送维持连接包,服务端程序将断开连接。

客户端:
通过持有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 = ;

        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 = ;

        long keepAliveDelay = ;

        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()>){

                        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();

                    }

                } 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 = ;

        Server server = new Server(port);

        server.start();

    }

    private int port;

    private volatile boolean running=false;

    private long receiveTimeDelay=;

    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,);

                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()>){

                            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();

                        }

                    } 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());

        }
}
}

socket长连接的维持的更多相关文章

  1. 基于心跳的socket长连接

    http://coach.iteye.com/blog/2024444 基于心跳的socket长连接 博客分类: http socket 案例: 心跳: socket模拟网页的报文连接某个网站,创建t ...

  2. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...

  3. android端 socket长连接 架构

    看过包建强的<App研发录>之后对其中的基础Activity类封装感到惊讶,一直想找一种方式去解决关于app中使用socket长连接问题,如何实现简易的封装来达到主活动中涉及socket相 ...

  4. 【Socket】关于socket长连接的心跳包

    TCP的socket本身就是长连接的,那么为什么还要心跳包呢? 在smack里有个30s发送一个空消息的线程,同样关于心跳包(keepalive) 据网络搜索到的资料解释如下 内网机器如果不主动向外发 ...

  5. 基于netty框架的socket长连接负载均衡解决方案

    socket通讯的单机瓶颈 物联网的项目socket使用方式有两种: 短连接的socket请求 维持socket长连接的请求 对于socket短链接来说就好比是http请求,请求服务器,服务器返回数据 ...

  6. iOS后台如何保持socket长连接和数据传输

    工程中使用tcp长连接来和服务端进行数据传输,在IOS平台上,由于苹果的后台机制,会有以下问题: 当程序退到后台的时候,所有线程被挂起,系统会回收所有的socket资源,那么socket连接就会被关闭 ...

  7. socket长连接理解

    在一个tcp连接上可以连续发送多个数据包,在tcp连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持. 长连接指建立socket连接后不管是否使用都保持连接,但安全 ...

  8. 6.1 socket 长连接、短连接

    一般情况下,服务器的长连接和短连接不是服务器说了算,而是客户端说了算.因为服务器是给别人提供业务的,一旦连接建立起来之后,服务器端不会主动把连接给close掉. 客户端发送一笔业务,没有关闭连接,然后 ...

  9. 使用http维持socket长连接

    项目中有遇到问题如下: 1.旧版的cs服务,因为每个用户和唯一的长连接是在登录后绑定的,并且所有的消息报文均是基于该长连接去发送接收的,所以要求node服务要维持一个长连接,然后根据该用户获取长连接, ...

  10. Socket长连接和短连接的区别

    https://blog.csdn.net/jasonjwl/article/details/52085264 短连接 连接->传输数据->关闭连接 HTTP是无状态的,浏览器和服务器每进 ...

随机推荐

  1. iOS Scheme 跳转主流实现方案

    iOS Scheme跳转主流实现方案主要是路由跳转,目前iOS常用路由框架是JLRouter.HHRouter.MGJRouter. 但是这些路由库都各有不足,首先是JLRouter,用不到的功能繁多 ...

  2. matlab中tic和toc使用方法

    tic和toc用来记录matlab命令运行的时间.  tic用来保存当前时间,而后使用toc来记录程序完毕时间. 两者往往结合使用,使用方法例如以下: 程序代码: tic  operations  t ...

  3. 9.9递归和动态规划(九)——N皇后

    /**  * 功能:打印八皇后在8*8棋盘上的各种摆法.当中每一个皇后都不同行.不同列,也不在对角线上.  * 这里的"对角线"指的是全部的对角线,不仅仅是平分整个棋盘的那两条对角 ...

  4. 自己写unicode转换ascii码,wchar*到char*

    对于ascii码的char事实上就是unicode码wchar的首个字节码, 如wchar[20] = "qqqq"; 在内存中排码事实上是char的'q' '\0'这类.因此我们 ...

  5. USACO milk

    /* ID:kevin_s1 PROG:milk LANG:C++ */ #include <iostream> #include <string> #include < ...

  6. 第二天,导出文件sql,查询,视图view,聚合函数,反模式,字符串处理函数

    //把数据库导出到脚本文件mysqldump -uroot -p1234 --databases abc > d:/a/abc.sql CREATE TABLE stud( id INT PRI ...

  7. adb-端口被占用解决办法(win)

    今天在window下使用adb的时候,提示我说5037端口被占用. * daemon not running. starting it now on port * ADB server didn't ...

  8. 如何动态改变audio的播放的src

    如何动态改变audio的播放的src 一.总结 一句话总结:js方式在请求外部网站的时候行,php方式在请求内外部资源都行.因为php走在js前面,所以问题可以从php方面想办法. 1.如何使用js控 ...

  9. Spark MLlib协同过滤算法

    算法说明 协同过滤(Collaborative Filtering,简称CF,WIKI上的定义是:简单来说是利用某个兴趣相投.拥有共同经验之群体的喜好来推荐感兴趣的资讯给使用者,个人透过合作的机制给予 ...

  10. Kinect 开发 —— 常见手势识别(下)

    划动(Swipe) 划动手势和挥手(wave)手势类似.识别划动手势需要不断的跟踪用户手部运动,并保持当前手的位置之前的手的位置.因为手势有一个速度阈值,我们需要追踪手运动的时间以及在三维空间中的坐标 ...