当前位置: 首页 > 编程日记 > 正文

JAVA实现长连接(含心跳检测)Demo

实现原理:

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

客户端:
       Client通过持有Socket的对象,可以随时(使用sendObject方法)发送Massage Object(消息)给服务端。
       如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则自动发送一个KeepAlive Object(心跳)给服务端,用于维持连接。
       由于,我们向服务端,可以发送很多不同的消息对象,服务端也可以返回不同的对象。所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。通过Client.addActionMap方法进行添加。这样,程序会回调处理。

服务端:
        由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。
        即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则自动断开与客户端的连接。
         ActionMapping的原理与客户端相似(相同)。

通过添加相应的ObjectAction实现类,可以实现不同对象的响应、应答过程。

心跳反映的代码:

*** * 维持连接的消息对象(心跳对象)*/
public class KeepAlive implements Serializable{private static final long serialVersionUID = -2813120366138988480L;/* 覆盖该方法,仅用于测试使用。* @see java.lang.Object#toString()*/@Overridepublic String toString() {return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"\t维持连接包";}}

客户端的代码:

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();  //保持长连接的线程,每隔2秒项服务器发一个一个保持连接的心跳消息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();} }}}}

服务短的代码:

public class Server {/*** 要处理客户端发来的对象,并返回一个对象,可实现该接口。*/public interface ObjectAction{Object doAction(Object rev, Server server);}public static final class DefaultObjectAction implements ObjectAction{public Object doAction(Object rev,Server server) {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,Server.this);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());}}}

转载于:https://www.cnblogs.com/zqyanywn/p/7171969.html

相关文章:

java开发环境变量配置-JDK11-(win10),重启之后环境变量配置失效的解决办法

win10安装jdk11及环境变量配置 如果你之前已经安装过java的老版本的话&#xff0c;建议先卸载一下&#xff0c;同时删除掉环境变量的配置&#xff0c;这样比较容易一次性成成功&#xff0c;直接到设置里面应用程序找到java卸载就好 下载JDK11 直接附上官网链接&#xff1a;htt…

Activity启动流程图

转载于:https://www.cnblogs.com/dikeboy/p/10064610.html

sql 70-229 考试样题(1)

转&#xff1a;1&#xff0e;你是一数据公司的数据库开发者&#xff0c;你创建了一个用来存储15个不同高校运动会统计表的数据库。这些信息将被用在50家公司的网页设置上。每个公司的WEB设置以不同的格式来安排和显示这些统计表。你需要组装这些数据传送到这些公司去&#xff0…

HDU 5616 Jam's balance(01背包)

题目网址&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid5616 题目&#xff1a; Jams balance Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1810 Accepted Submission(s): 754 Problem Description…

datagrid DataFormatString

DataFormatString格式字符串 DataFormatString"{0:格式字符串}" 在DataFormatString 中的 {0} 表示数据本身&#xff0c;而在冒号后面的格式字符串代表所们希望数据显示的格式&#xff1b; 数字、货币格式&#xff1a;在指定的格式符号后可以指定小数所要显示的位数…

HashMap 和 Hashtable 的 6 个区别,最后一个没几个人知道!

HashMap 和 Hashtable 是 Java 开发程序员必须要掌握的&#xff0c;也是在各种 Java 面试场合中必须会问到的。 但你对这两者的区别了解有多少呢&#xff1f; 现在&#xff0c;栈长我给大家总结一下&#xff0c;或许有你不明朗的地方&#xff0c;在栈长的指点下都会拨开迷雾见晴…

自学笔记——Python内置的处理字符串的函数

序号函数描述1capitalize() 字符串的首字母变为大写2center&#xff08;width, fillchar&#xff09; 返回原来的字符串&#xff08;居中&#xff09;&#xff0c;并以空格填充至特定长度的字符串3count( str ,beg 0, end len(string) )计算出str在字符串中出现的字数&#x…

办公室28个经典赞美句子【转】

1.you look great today.&#xff08;你今天看上去很棒。&#xff09;【每天都可以用&#xff01;】2. you did a good job. &#xff08;你干得非常好。&#xff09;【国际最通用的表扬&#xff01;】3. we’re so proud of you.&#xff08;我们十分为你骄傲。&#xff09;【…

[源码和文档分享]基于java 的仿QQ聊天工具

一 需求分析 本系统是基于java开发的聊天室。有用户注册、用户登陆、修改密码、忘记密码、添加好友、用户聊天、群聊功能。如果服务器还没有启动&#xff0c;则客户端是不可以登陆、注册、忘记密码&#xff0c;如果在运行过程中&#xff0c;服务器断开则系统会有提示&#xff0…

错误: 编码 GBK 的不可映射字符 (0x80)

在我想要在命令行使用println输出一些中文的时候&#xff0c;发现编码出现错误 原因&#xff1a; java程序在编译的时候&#xff0c;需要使用JDK开发工具包中的JAVAC.EXE命令&#xff0c;而JDK开发工具包是国际版的&#xff0c;默认格式为UNICODE的编码格式。因此在默认情况下&…

HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)

传送门 Description 急&#xff01;灾区的食物依然短缺&#xff01;为了挽救灾区同胞的生命&#xff0c;心系灾区同胞的你准备自己采购一些粮食支援灾区&#xff0c;现在假设你一共有资金n元&#xff0c;而市场有m种大米&#xff0c;每种大米都是袋装产品&#xff0c;其价格不等…

A simple class to play sound on netcf (part 2)

在实际测试中发现上一片文章&#xff08;A simple class to play sound on netcf&#xff09;中介绍的播放声音的类在pda中运行正常&#xff0c;但却无法在pc中工作&#xff0c;简单分析了一下原因&#xff0c;发现是dll的问题&#xff0c;pc和pda播放声音时用的dll不同。pc中是…

SSL证书可以给多个域名使用吗?

欢迎访问网易云社区&#xff0c;了解更多网易技术产品运营经验从信任等级的角度来说&#xff0c;SSL证书主要分为三类&#xff1a;1.域名型https证书&#xff08;DVSSL&#xff09;:信任等级一般&#xff0c;只需验证网站的真实性便可颁发证书保护网站&#xff1b;2. 企业型htt…

ASP.NET性能调整之解决Server Too Busy错误

最近公司的一个ASP.NET站点频繁出现Server Too Busy错误&#xff0c;具体表现为页面响应慢、经常出现Server Too Busy异常&#xff1b;但实际上服务器的资源消耗却很低&#xff0c;CPU使用只有10%左右&#xff0c;非常奇怪。 该站点运行环境为Windows 2000&#xff0c;IIS5.0&a…

IDEA 格式化代码Reform Code快捷键无效

** 看着用起来这么舒服的IDEA快捷键&#xff0c;突然CtrlAltL怎么按都没有反应&#xff0c;瞬间就不香了** 不行&#xff0c;我要搞一下 解决办法 快捷键冲突 一边学习IDEA&#xff0c;一遍你听歌多舒服啊&#xff0c;就是这个东西——“”“网易云音乐&#xff08;当然或者其他…

ajax方法参数

jquery中的ajax方法参数总是记不住&#xff0c;这里记录一下。 1.url: 要求为String类型的参数&#xff0c;&#xff08;默认为当前页地址&#xff09;发送请求的地址。 2.type: 要求为String类型的参数&#xff0c;请求方式&#xff08;post或get&#xff09;默认为get。注意其…

“解决方案资源管理器”中不能自动选择正在编辑的文档

本来正在编辑的文档应该在“解决方案资源管理器”中自动选中的&#xff0c;但是我的VS2005机器好像没有这个功能&#xff0c;后来发现 “工具->选贤”里边的“项目和解决方案->常规”里边有一项“在解决方案资源管理器中跟踪活动项”&#xff0c;选中后问题解决。VS2003也…

打造属于自己的underscore系列 ( 一 )

underscore作为开发中比较常用的一个javascript工具库&#xff0c;提供了一套丰富的函数式编程功能&#xff0c;该库并没有拓展原有的javascript原生对象&#xff0c;而是在自定义的_对象上&#xff0c;提供了100多个方法函数。在这个系列中&#xff0c;将从uderscore源码角度&…

Java案例——字符串拼接

Java案例——字符串拼接案例 1.案例需求 定义一个方法&#xff0c;把int数组中的数据按照指定的格式拼接成一个字符串返回&#xff0c;调用该方法&#xff0c;并在控制台输出结果 例如&#xff0c;数字为int[] arr {1,2,3};执行方法后的输出结果为&#xff1a;[1,2,3] 2.思路…

SQL同时删除两张表中的数据

DELETE user,orders from user,orders where user.idorders.user_id AND user.id#{id}; 转载于:https://www.cnblogs.com/duneF/p/7196472.html

安全与用户输入

用户数据&#xff0c;就是任何种类的输入&#xff08;来自于 Web 请求或者 URL 中的数据&#xff0c;输入在 Microsoft Windows 窗体应用程序的控件中的数据&#xff0c;等等&#xff09;&#xff0c;它能够对代码产生影响&#xff0c;因为这些数据经常被直接当成参数来使用并且…

谁能搞定中国的文艺复兴,我就能搞定中国的政治改革

文化--------------经济------------------政治转载于:https://blog.51cto.com/73945/12249

构造函数以及this

实际上构造函数与普通的函数并没有区别&#xff0c;所以一般在开发中会使用大驼峰命名规则来区别普通的函数&#xff0c;构造函数实际上是通过返回一个this值来完成构造函数的创建的. 这个rutern this的操作由new这个操作符来完成&#xff0c;当然个人也可以手动来设置return的…

java案例——字符串反转

java案例——字符串反转 1.需求&#xff1a; 定义一个方法&#xff0c;实现字符串反转。键盘录入一个字符串&#xff0c;调用该方法后&#xff0c;在控制台输出结果 例如&#xff0c;键盘录入abc,输出结果cba2.思路&#xff1a; 1.键盘录入一个字符串&#xff0c;用Scanner实…

Jetson tk1 安装 CUDA,ROS,OpenCV和kinect2以及刷机以及ssh远程控制

我的jetson tk1的系统是&#xff1a;LTR21.3&#xff0c;ubuntu14.04。本文仅仅是个人总结&#xff0c;亲测成功。 注意&#xff1a;如果你是使用校园网进行安装的话&#xff0c;有很多源是没办法访问的&#xff0c;安装的时候就会出现很多问题&#xff0c;所以&#xff0c;尽量…

Refactor!™ for ASP.NET--ASP.NET代码重构插件

Teaching Demo: http://www.devexpress.com/Products/NET/IDETools/CodeRush/Training.xml有些功能在JBuilder2005中早就有了。大家了解一下吧&#xff0c;比较不错。Refactor! is freely available to all ASP.NET 2.0 developers and offers a comprehensive suite of tools …

面向对象的程序开发技术C++教学课件系列之四

面向对象的程序开发技术C教学课件系列之四转载于:https://blog.51cto.com/hnxdd/13205

python自动华 (十四)

Python自动化 【第十四篇】&#xff1a;HTML介绍 本节内容&#xff1a; Html概述HTML文档常用标签2. CSS 概述CSS选择器CSS常用属性1.HTML 1.1概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写&#xff0c;他是一种制作万维网页面标准语言&#xff08;标记&a…

一些有趣的题目(java)持续更新

有趣的编程题1.面试题2.某公司面试题1.面试题 此处为正确的代码 package Java.king01.Test;class MicrosoftTest {public static void main(String[] args) {int[] arr new int[]{12,3,3,34,56,78,432};for(int i arr.length - 1;i > 0;i--){arr[i] arr[i]/arr[0];}for(…

lunix开放端口

以mysql服的3306端口为例。 1、直接打开端口&#xff1a;iptables -I INPUT -p tcp --dport 3306 -j ACCEPT 2、永久打开某端口首先&#xff0c;用vim打开防火墙配置文件&#xff1a;vim /etc/sysconfig/iptables然后&#xff0c;在iptables文件内容中加入如下内容:-A RH-Firew…