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

客户端:
通过持有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. 数据持久化-存取方式总结&应用沙盒&文件管理NSFileManager

    iOS应用数据存储的常用方式:  1.XML属性列表   (plist归档)  2.NSUserDefaults (偏好设置)  3.NSKeyedArchiver  归档(加密形式)  4.SQLi ...

  2. 关于结构体内存对齐方式的总结(#pragma pack()和alignas())

    最近闲来无事,翻阅msdn,在预编译指令中,翻阅到#pragma pack这个预处理指令,这个预处理指令为结构体内存对齐指令,偶然发现还有另外的内存对齐指令aligns(C++11),__declsp ...

  3. CCF模拟题 窗口

    窗口 时间限制: 1.0s 内存限制: 256.0MB   问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口.窗口之间有层次的 ...

  4. redis练习手册<二>快速入门

    Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的Web应用程序的完美解决方案. Redis从它的许多竞争继承来的三个主要特点: Redis数据库完全在内存中,使用磁盘仅用 ...

  5. 修正EasyUI的BUG——Form中存在FileBox时的数据载入错误

    使用EasyUI载入服务端返回的数据时经常使用 $('#fm').form('load', row); 实现,既方便又简洁,可是.当Form中包括有FileBox时,代码就会报错,经过跟踪发现.由于E ...

  6. vue1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. CRSF Defense Using Content Injection Support By ModSecurity

    The most advanced and imaginative use of the content injection feature is that devised byRyan C. Bar ...

  8. 6.Maven之(六)setting.xml配置文件详解

    转自:https://blog.csdn.net/u012152619/article/details/51485152

  9. TOJ 2233 WTommy's Trouble

    2233.   WTommy's Trouble Time Limit: 2.0 Seconds   Memory Limit: 65536KTotal Runs: 1499   Accepted R ...

  10. 【Mysql】将Excel表导入至Mysql的当中一张表

    如果表格有A(整型字段).B(整型字段).C(字符串数据)三列数据,希望导入到Mysql中数据库中表格table.table中须要插入的字段各自是col1,col2,col3 1.在随意一列,如果在D ...