精华内容
下载资源
问答
  • Socket心跳连接_java

    2016-02-20 21:38:36
    主要是关于java tcp长连接,心跳连接源码。
  • 前言可能很多 Java 程序员对 TCP 的理解只有一个...其实我个人对 TCP 的很多细节也并没有完全理解,这篇文章主要针对微信交流群里有人提出的长连接心跳的问题,做一个统一的整理。在 Java 中,使用 TCP 通信,大概...

    前言

    可能很多 Java 程序员对 TCP 的理解只有一个三次握手,四次握手的认识,我觉得这样的原因主要在于 TCP 协议本身稍微有点抽象(相比较于应用层的 HTTP 协议);其次,非框架开发者不太需要接触到 TCP 的一些细节。其实我个人对 TCP 的很多细节也并没有完全理解,这篇文章主要针对微信交流群里有人提出的长连接,心跳的问题,做一个统一的整理。

    8eb13f3e46dd15898b4062bbc63ec0d9.png

    在 Java 中,使用 TCP 通信,大概率会涉及到 Socket、Netty,本文会借用它们的一些 API 和设置参数来辅助介绍。

    长连接与短连接

    TCP 本身并没有长短连接的区别,长短与否,完全取决于我们怎么用它。

    短连接:每次通信时,创建 Socket;一次通信结束,调用 socket.close()。这就是一般意义上的短连接,短连接的好处是管理起来比较简单,存在的连接都是可用的连接,不需要额外的控制手段。

    长连接:每次通信完毕后,不会关闭连接,这样就可以做到连接的复用。长连接的好处便是省去了创建连接的耗时。

    短连接和长连接的优势,分别是对方的劣势。想要图简单,不追求高性能,使用短连接合适,这样我们就不需要操心连接状态的管理;想要追求性能,使用长连接,我们就需要担心各种问题:比如端对端连接的维护,连接的保活。

    长连接还常常被用来做数据的推送,我们大多数时候对通信的认知还是 request/response 模型,但 TCP 双工通信的性质决定了它还可以被用来做双向通信。在长连接之下,可以很方便的实现 push 模型。

    短连接没有太多东西可以讲,所以下文我们将目光聚焦在长连接的一些问题上。纯讲理论未免有些过于单调,所以下文我借助 Dubbo 这个 RPC 框架的一些实践来展开 TCP 的相关讨论。

    服务治理框架中的长连接

    前面已经提到过,追求性能的时候,必然会选择使用长连接,所以借助 Dubbo 可以很好的来理解 TCP。我们开启两个 Dubbo 应用,一个 server 负责监听本地 20880(众所周知,这是 Dubbo 协议默认的端口),一个 client 负责循环发送请求。执行lsof -i:20880命令可以查看端口的相关使用情况:

    34c79f53d768a1b16ca4980ae12c279e.png

    image-20190106203341694

    *:20880 (LISTEN)说明了 Dubbo 正在监听本地的 20880 端口,处理发送到本地 20880 端口的请求

    后两条信息说明请求的发送情况,验证了 TCP 是一个双向的通信过程,由于我是在同一个机器开启了两个 Dubbo 应用,所以你能够看到是本地的 53078 端口与 20880 端口在通信。我们并没有手动设置 53078 这个客户端端口,他是随机的,但也阐释了一个道理:即使是发送请求的一方,也需要占用一个端口。

    稍微说一下 FD 这个参数,他代表了文件句柄,每新增一条连接都会占用新的文件句柄,如果你在使用 TCP 通信的过程中出现了open too many files的异常,那就应该检查一下,你是不是创建了太多的连接,而没有关闭。细心的读者也会联想到长连接的另一个好处,那就是会占用较少的文件句柄。

    长连接的维护

    因为客户端请求的服务可能分布在多个服务器上,客户端端自然需要跟对端创建多条长连接,使用长连接,我们遇到的第一个问题就是要如何维护长连接。

    @Sharable

    publicclass NettyHandler extends SimpleChannelHandler {

    private final Map channels = new ConcurrentHashMap(); // 

    }

    publicclass NettyServer extends AbstractServer implements Server {

    private Map channels; // 

    }

    在 Dubbo 中,客户端和服务端都使用ip:port维护了端对端的长连接,Channel 便是对连接的抽象。我们主要关注 NettyHandler 中的长连接,服务端同时维护一个长连接的集合是 Dubbo 的设计,我们将在后面提到。

    连接的保活

    这个话题就有的聊了,会牵扯到比较多的知识点。首先需要明确一点,为什么需要连接的报活?当双方已经建立了连接,但因为网络问题,链路不通,这样长连接就不能使用了。需要明确的一点是,通过 netstat,lsof 等指令查看到连接的状态处于ESTABLISHED状态并不是一件非常靠谱的事,因为连接可能已死,但没有被系统感知到,更不用提假死这种疑难杂症了。如果保证长连接可用是一件技术活。

    连接的保活:KeepAlive

    首先想到的是 TCP 中的 KeepAlive 机制。KeepAlive 并不是 TCP 协议的一部分,但是大多数操作系统都实现了这个机制。KeepAlive 机制开启后,在一定时间内(一般时间为 7200s,参数tcp_keepalive_time)在链路上没有数据传送的情况下,TCP 层将发送相应的KeepAlive探针以确定连接可用性,探测失败后重试 10(参数tcp_keepalive_probes)次,每次间隔时间 75s(参数tcp_keepalive_intvl),所有探测失败后,才认为当前连接已经不可用。

    在 Netty 中开启 KeepAlive:

    bootstrap.option(ChannelOption.SO_KEEPALIVE, true)

    Linux 操作系统中设置 KeepAlive 相关参数,修改/etc/sysctl.conf文件:

    net.ipv4.tcp_keepalive_time=90

    net.ipv4.tcp_keepalive_intvl=15

    net.ipv4.tcp_keepalive_probes=2

    KeepAlive 机制是在网络层面保证了连接的可用性,但站在应用框架层面我们认为这还不够。主要体现在两个方面:

    KeepAlive 的开关是在应用层开启的,但是具体参数(如重试测试,重试间隔时间)的设置却是操作系统级别的,位于操作系统的/etc/sysctl.conf配置中,这对于应用来说不够灵活。

    KeepAlive 的保活机制只在链路空闲的情况下才会起到作用,假如此时有数据发送,且物理链路已经不通,操作系统这边的链路状态还是 ESTABLISHED,这时会发生什么?自然会走 TCP 重传机制,要知道默认的 TCP 超时重传,指数退避算法也是一个相当长的过程。

    KeepAlive 本身是面向网络的,并不是面向于应用的,当连接不可用时,可能是由于应用本身 GC 问题,系统 load 高等情况,但网络仍然是通的,此时,应用已经失去了活性,所以连接自然应该认为是不可用的。

    看来,应用层面的连接保活还是必须要做的。

    连接的保活:应用层心跳

    终于点题了,文题中提到的心跳便是一个本文想要重点强调的另一个 TCP 相关的知识点。上一节我们已经解释过了,网络层面的 KeepAlive 不足以支撑应用级别的连接可用性,本节就来聊聊应用层的心跳机制是实现连接保活的。

    如何理解应用层的心跳?简单来说,就是客户端会开启一个定时任务,定时对已经建立连接的对端应用发送请求(这里的请求是特殊的心跳请求),服务端则需要特殊处理该请求,返回响应。如果心跳持续多次没有收到响应,客户端会认为连接不可用,主动断开连接。不同的服务治理框架对心跳,建连,断连,拉黑的机制有不同的策略,但大多数的服务治理框架都会在应用层做心跳,Dubbo 也不例外。

    应用层心跳的设计细节

    以 Dubbo 为例,支持应用层的心跳,客户端和服务端都会开启一个HeartBeatTask,客户端在HeaderExchangeClient中开启,服务端将在HeaderExchangeServer开启。文章开头埋了一个坑:Dubbo 为什么在服务端同时维护Map呢?主要就是为了给心跳做贡献,心跳定时任务在发现连接不可用时,会根据当前是客户端还是服务端走不同的分支,客户端发现不可用,是重连;服务端发现不可用,是直接 close。

    // HeartBeatTask

    if (channel instanceof Client) {

    ((Client) channel).reconnect();

    } else{

    channel.close();

    }

    熟悉其他 RPC 框架的同学会发现,不同框架的心跳机制真的是差距非常大。心跳设计还跟连接创建,重连机制,黑名单连接相关,还需要具体框架具体分析。

    除了定时任务的设计,还需要在协议层面支持心跳。最简单的例子可以参考 nginx 的健康检查,而针对 Dubbo 协议,自然也需要做心跳的支持,如果将心跳请求识别为正常流量,会造成服务端的压力问题,干扰限流等诸多问题。

    1c1d74ac13c0f7939d5cbbbd83ed9696.png

    dubbo protocol

    其中 Flag 代表了 Dubbo 协议的标志位,一共 8 个地址位。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为1表示是 request 请求,第二位为 1 表示双向传输(即有返回response),第三位为 1 表示是心跳事件。

    心跳请求应当和普通请求区别对待。

    注意和 HTTP 的 KeepAlive 区别对待

    HTTP 协议的 KeepAlive 意图在于连接复用,同一个连接上串行方式传递请求-响应数据

    TCP 的 KeepAlive 机制意图在于保活、心跳,检测连接错误。

    这压根是两个概念。

    KeepAlive 常见错误

    启用 TCP KeepAlive 的应用程序,一般可以捕获到下面几种类型错误

    ETIMEOUT 超时错误,在发送一个探测保护包经过 (tcp_keepalive_time + tcp_keepalive_intvl * tcp_keepalive_probes)时间后仍然没有接收到 ACK 确认情况下触发的异常,套接字被关闭

    java.io.IOException: Connection timed out

    EHOSTUNREACH host unreachable(主机不可达)错误,这个应该是 ICMP 汇报给上层应用的。

    java.io.IOException: No route to host

    链接被重置,终端可能崩溃死机重启之后,接收到来自服务器的报文,然物是人非,前朝往事,只能报以无奈重置宣告之。

    java.io.IOException: Connection reset by peer

    总结

    有三种使用 KeepAlive 的实践方案:

    默认情况下使用 KeepAlive 周期为 2 个小时,如不选择更改,属于误用范畴,造成资源浪费:内核会为每一个连接都打开一个保活计时器,N 个连接会打开 N 个保活计时器。 优势很明显:

    TCP 协议层面保活探测机制,系统内核完全替上层应用自动给做好了

    内核层面计时器相比上层应用,更为高效

    上层应用只需要处理数据收发、连接异常通知即可

    数据包将更为紧凑

    关闭 TCP 的 KeepAlive,完全使用应用层心跳保活机制。由应用掌管心跳,更灵活可控,比如可以在应用级别设置心跳周期,适配私有协议。

    业务心跳 + TCP KeepAlive 一起使用,互相作为补充,但 TCP 保活探测周期和应用的心跳周期要协调,以互补方可,不能够差距过大,否则将达不到设想的效果。

    各个框架的设计都有所不同,例如 Dubbo 使用的是方案三,但阿里内部的 HSF 框架则没有设置 TCP 的 KeepAlive,仅仅由应用心跳保活。和心跳策略一样,这和框架整体的设计相关。

    【编辑推荐】

    【责任编辑:武晓燕 TEL:(010)68476606】

    点赞 0

    展开全文
  • 简单解释就是:短连接:建立连接,发送数据包,关闭连接连接:建立连接,发送数据包,发送心跳包,发送数据包,发送心跳包,发送心跳包。。。。。。所以又频繁的数据收发的话,短连接会频繁创建TCP连接,而对于长...

    简单解释就是:

    短连接:建立连接,发送数据包,关闭连接

    长连接:建立连接,发送数据包,发送心跳包,发送数据包,发送心跳包,发送心跳包。。。。。。

    所以又频繁的数据收发的话,短连接会频繁创建TCP连接,而对于长连接,则始终用的是同一个TCP连接

    package com.tree.demo.socket;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

    public class ServerSocketDemo {

    private static final int PORT = 1234;

    private static final int BUFFER_SIZE = 1024;

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    try {

    ServerSocket ss = new ServerSocket(PORT);

    Socket s = ss.accept();

    System.out.println("这是服务端,监听本机"+PORT+"端口");

    byte[] recData = null;

    InputStream in = s.getInputStream();

    OutputStream out = s.getOutputStream();

    while(true) {

    recData = new byte[BUFFER_SIZE];

    int r = in.read(recData);

    //int r = in.read(recData);

    if(r>-1) {

    String data = new String(recData);

    if(data.trim().equals("over")) {

    s.close();

    }

    System.out.println("读取到客户端发送的来数据:"+data);

    out.write("这是服务端发给客户端的数据:".getBytes());

    out.write(recData);

    }else {

    System.out.println("数据读取完毕!");

    s.close();

    System.exit(0);

    //ss.close();

    }

    }

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    df9a90c2d629c460a1084f0f23dc6db9.png

    以上这种服务端读数据是阻塞式,如果客户端没有数据写过来,服务端就会一直阻塞在那不动

    客户端开启一个telnet即可测试服务端的socket程序了,当然你也可以自己写一个socket客户端,如下:

    package socket;

    import java.io.IOException;

    import java.io.OutputStream;

    import java.net.Socket;

    import java.net.UnknownHostException;

    public class ClientSocketDemo {

    private static final String HOST = "192.168.8.14";

    private static final int PORT = 1234;

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

    IOException {

    Socket client = new Socket(HOST, PORT);

    OutputStream out = client.getOutputStream();

    try {

    while (true) {

    Thread.sleep(1000);

    System.out.println("发送心跳数据包");

    out.write("send heart beat data package !".getBytes());

    }

    } catch (Exception e) {

    e.printStackTrace();

    out.close();

    client.close();

    }

    }

    }同时这要是一个心跳的实例,心跳只要不出现异常的情况下,可以直接使用client连接发送数据包,不需要new socket新建连接了。

    原文:http://blog.csdn.net/simonchi/article/details/40613923

    展开全文
  • 实现原理:长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。如果,长时间未发送维持...如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则自动发送一个KeepAlive Object(心跳)给服务...

    实现原理:

    长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。

    如果,长时间未发送维持连接包,服务端程序将断开连接。

    客户端:

    Client通过持有Socket的对象,可以随时(使用sendObject方法)发送Massage Object(消息)给服务端。

    如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则自动发送一个KeepAlive Object(心跳)给服务端,用于维持连接。

    由于,我们向服务端,可以发送很多不同的消息对象,服务端也可以返回不同的对象。所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。通过Client.addActionMap方法进行添加。这样,程序会回调处理。

    服务端:

    由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。

    即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则自动断开与客户端的连接。

    ActionMapping的原理与客户端相似(相同)。

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

    Demo:

    package socket.keepalive.test;

    import java.io.Serializable;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    /**

    *

    * 维持连接的消息对象(心跳对象)

    */

    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维持连接包";

    }

    }

    package socket.keepalive.test;

    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.Collections;

    import java.util.concurrent.ConcurrentHashMap;

    /**

    * C/S架构的客户端对象,持有该对象,可以随时向服务端发送消息。

    *

    * 创建时间: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 actionMapping = new ConcurrentHashMap();

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

    }

    }

    }

    }

    }

    package socket.keepalive.test;

    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架构的服务端对象。

    *

    * 创建时间:2010-7-18 上午12:17:37

    * @author HouLei

    * @since 1.0

    */

    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 actionMapping = new ConcurrentHashMap();

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

    }

    }

    }

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持聚米学院。

    展开全文
  • Java 心跳 Socket 长连接

    2015-03-12 11:00:43
    package com.trancomm.socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.
    package com.trancomm.socket;


    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    import java.util.Timer;
    import java.util.TimerTask;


    public class SuperClient 
    {
    private final String ip="127.0.0.1"; // 127.0.0.1
    private final int port=5856; // 5856请求,5859更新
    private Socket socket=null;
    private boolean isConnected=false;
    private InputStream inputStream=null;
    private OutputStream outputStream=null;
    private byte[] receiveBuffer=new byte[1024*100];

    private Timer timer=new Timer(true);
    private final int TIMER_HEARTTIME=30;
    private int timeOut=TIMER_HEARTTIME;

    private static SuperClient instance=null;

    private SuperClient()
    {
    timer.schedule(new TimerTask()
    {
    @Override
    public void run() 
    {
    if(timeOut<1)
    {
    // TODO 发送心跳
    //调用send 发送心跳
    String str="心跳字符串";
    send(str);
    timeOut=TIMER_HEARTTIME;
    }
    timeOut--;
    }
    }
    , 0, 1000);
    }

    public synchronized static SuperClient getInstance()
    {
    if(null==instance)
    {
    instance=new SuperClient();
    }
    return instance;
    }

    public boolean Connect()
    {
    if(isConnected)
    {
    return isConnected;
    }
    ClientThread clientThread=new ClientThread();
    Thread thread=new Thread(clientThread);
    thread.start();
    return isConnected;
    }

    private void DisConnect()
    {
    isConnected=false;
    try
    {
    if(null!=socket)
    {
    socket.close();
    socket=null;
    }
    }
    catch(Exception ex)
    {

    }
    }

    public boolean send(String str)
    {
    try
    {
    Connect();
    if(isConnected)
    {
    synchronized (this)
    {
    byte[] data=str.getBytes("UTF-8");
    outputStream=socket.getOutputStream();
    outputStream.write(data);
    outputStream.flush();
    return true;
    }
    }
    }
    catch(IOException e1)
    {
    DisConnect();
    }
    catch(Exception e2)
    {
    DisConnect();
    }
    return false;
    }

    class ClientThread implements Runnable
    {
    @Override
    public void run() 
    {
    try
    {
    if(null!=socket)
    {
    socket.close();
    socket=null;
    }
    socket=new Socket();
    socket.connect(new InetSocketAddress(InetAddress.getByName(ip), port));
    inputStream=socket.getInputStream();
    isConnected=true;
    ReceiveThread receiveThread=new ReceiveThread();
    Thread thread=new Thread(receiveThread);
    thread.start();
    }
    catch(UnknownHostException e1)
    {
    DisConnect();
    }
    catch(IOException e2)
    {
    DisConnect();
    }
    catch(Exception e3)
    {
    DisConnect();
    }
    }
    }

    class ReceiveThread implements Runnable
    {
    @Override
    public void run()
    {
    while(isConnected)
    {
    try
    {
    int reads=inputStream.read(receiveBuffer, 0, receiveBuffer.length);
    if(reads==-1)
    {
    DisConnect();
    }
    else
    {
    byte[] buffer=Arrays.copyOfRange(receiveBuffer, 0, reads);
    String str=new String(buffer);
    // TODO 解析str
       //对接收到的字符串进行相应的处理
    }
    }
    catch(IOException e1)
    {
    DisConnect();
    }
    catch(Exception e2)
    {
    DisConnect();
    }
    }
    }
    }

    }



    //使用方法SuperClient.getInstance().Connect(); 建立连接   

    //发送数据

    SuperClient.getInstance().send(poststr);

    展开全文
  • 简单解释就是:短连接:建立连接,发送数据包,关闭连接连接:建立连接,发送数据包,发送心跳包,发送数据包,发送心跳包,发送心跳包。。。。。。所以又频繁的数据收发的话,短连接会频繁创建TCP连接,而对于长...
  • TCP连接简介当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接连接的建立是需要三次握手的,而释放则需要4...
  • public classServer {/*** 要处理客户端发来的对象,并返回一个对象,可实现该接口。*/public interfaceObjectAction{Object doAction(Object rev, Server server);}public static final class DefaultObjectAction ...
  • 简单解释就是:短连接:建立连接,发送数据包,关闭连接连接:建立连接,发送数据包,发送心跳包,发送数据包,发送心跳包,发送心跳包。。。。。。所以又频繁的数据收发的话,短连接会频繁创建TCP连接,而对于长...
  • 心跳机制心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。大部分CS的应用需要心跳机制。心跳机制一般在Server和Client都要实现,两者实现原理基本一样。Client不...
  • Minma是英文Minma Is Not Mina的简称该框架采用Java NIO的核心技术,实现了基于事件驱动的多线程异步通信框架,支持常见的长连接(腾讯QQ)和短连接(http通信)对于开发人员而言,所有的底层技术都是透明的,开发人员...
  • 实现原理:长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。如果,长时间未发送维持...如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则自动发送一个KeepAlive Object(心跳)给服务...
  • 前言由于工作需要使用到ftp服务,一开始是每次建立ftp连接,上传文件成功后,再释放连接,后来发现这个方法太浪费资源和时间了,就想到了使用ftp连接池的方式实现,这样,预先创建好ftp连接池,需要上传的时候从池子...
  • TCP连接简介当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接连接的建立是需要三次握手的,而释放则需要4...
  • import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;/*** @author 某家:* @version 创建时间:2015年8月17日 下午3...
  • java心跳发送

    2017-08-08 18:43:00
    java心跳发送: 大家都知道。如果你在互联网公司,并且开发的是产品那你一定接触不到。心跳机制。心跳包 那什么是心跳机制呢? 心跳机制就是定时发送一个自定义的结构体(心跳包)。确保连接的有效的机制。 大部分...
  • //保持长连接的线程,每隔2秒项服务器发一个一个保持连接心跳消息 new Thread(new ReceiveWatchDog()).start(); //接受消息的线程,处理消息 } public void stop(){ if(running)running=false; } /** * 添加接收...
  • 心跳机制心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。大部分CS的应用需要心跳机制。心跳机制一般在Server和Client都要实现,两者实现原理基本一样。Client不...
  • public classServer {/*** 要处理客户端发来的对象,并返回一个对象,可实现该接口。*/public interfaceObjectAction{Object doAction(Object rev, Server server);}public static final class DefaultObjectAction ...
  • JAVA实现长连接心跳检测 Demo
  • java socket 长连接 心跳

    千次阅读 2018-06-02 16:19:01
    首先先说说心跳包在socket连接中的意义: 通过socket连接的双方为了保证在一段时间未发消息不被防火墙断开连接或者使对方及时知道自己是否已经断线而定期给对方发送的某些特殊标识字符,这个字符可以根据双方自定义...
  • java心跳机制

    千次阅读 2017-12-10 02:21:29
    心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。 什么是心跳机制? 就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内...
  • 连接:建立连接,发送数据包,发送心跳包,发送数据包,发送心跳包,发送心跳包。。。。。。 所以又频繁的数据收发的话,短连接会频繁创建TCP连接,而对于长连接,则始终用的是同一个TCP连接 [java]...
  • http://www.blogjava.net/yongboy/archive/2014/02/09/409630.html2014前言本篇会把连接(CONNECT)、心跳(PINGREQ/PINGRESP)、确认(CONNACK)、断开连接(DISCONNECT)和在一起。CONNECT像前面所说,MQTT有关字符串部分...
  • [java] view plain copy package houlei.csdn.keepalive;    import java.io.Serializable;  import java.text.SimpleDateFormat;... * 维持连接的消息对象。   *    * 创建时间:2010-7-1

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 448
精华内容 179
关键字:

java心跳连接

java 订阅