实现TCP自动重连

网络重启、已连接端口掐灭可自动重连。

Java实现的Demo代码如下:

package top.onefine.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 发送模拟数据,可以自动重连
 *
 * @author one fine<br/>
 */
public class SendImitateData {
    
    
    public static final String HOST_ = "127.0.0.1";
    public static final int PORT_ = 11222;
    public static final int TIME_OUT = 30 * 1000;

    public static void main(String[] args) throws InterruptedException {
    
    
        Socket socket;
        while (true) {
    
    
            CyclicBarrier barr = new CyclicBarrier(3);
            System.out.println("connecting to Server " + HOST_ + ":" + PORT_);

            socket = initSocket();
            if (socket != null && socket.isConnected() && !socket.isClosed()) {
    
    
                System.out.println("connected...");

                OutThread out = new OutThread(barr, socket);
                out.start();

                InThread in = new InThread(barr, socket);
                in.start();

                try {
    
    
                    barr.await();  // 第一次,等着
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }

            } else {
    
    
                System.out.println("connected failed, sleep for 10 s!");
                Thread.sleep(10 * 1000);
            }

            barr.reset();  // 重置
        }
    }

    private static Socket initSocket() {
    
    
        Socket socket;
        try {
    
    
            socket = new Socket();
            socket.connect(new InetSocketAddress(HOST_, PORT_), TIME_OUT);
        } catch (IOException e) {
    
    
            return null;
        }
        return socket;
    }
}

class OutThread extends Thread {
    
    
    private Socket socket;
    private CyclicBarrier barr;

    public OutThread(CyclicBarrier barr, Socket socket) {
    
    
        this.barr = barr;
        this.socket = socket;
    }

    @Override
    public void run() {
    
    
        boolean target = true;
        BufferedOutputStream bos = null;
        while (target) {
    
    
            try {
    
    
                assert socket != null;
                if (socket.isConnected() && !socket.isClosed()) {
    
    

                    bos = getBufferedOutputStream(socket);
                    assert bos != null;
                    bos.write(getCommandBytes());
                    bos.write(new byte[]{
    
    0x0d, 0x0a});
                    bos.flush();

                } else {
    
    
                    target = false;
                }
                Thread.sleep(1000 * 10);
            } catch (Exception e) {
    
    
                System.out.println("OutThread = " + e.getMessage());
                target = false;
            } finally {
    
    
                try {
    
    
                    if (bos != null) {
    
    
                        bos.close();
                    }
                    if (socket != null) {
    
    
                        socket.close();
                    }
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }
        }
        try {
    
    
            barr.await();  // 第二次,等着
        } catch (InterruptedException | BrokenBarrierException e) {
    
    
            e.printStackTrace();
        }
    }

    private static BufferedOutputStream getBufferedOutputStream(Socket socket) {
    
    
        try {
    
    
            return new BufferedOutputStream(socket.getOutputStream());
        } catch (IOException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

    private static byte[] getCommandBytes() {
    
    
        StringBuilder command = new StringBuilder("##00000");
        command.append(";A0=").append(getRandomFloat());
        command.append(";A1=").append(getRandomFloat());
        command.append(";B0=").append(getRandomFloat());
        command.append(";C0=").append(getRandomFloat());
        command.append(";C1=").append(getRandomFloat());
        command.append(";C2=").append(getRandomFloat());
        command.append(";C3=").append(getRandomFloat());
        System.out.println(command.toString());
        return command.toString().getBytes();
    }

    private static Float getRandomFloat() {
    
    
        Random random = new Random();
        return BigDecimal.valueOf(random.nextDouble() * 100).setScale(2, RoundingMode.UP).floatValue();
    }

}

class InThread extends Thread {
    
    
    private Socket socket;
    private CyclicBarrier barr;

    public InThread(CyclicBarrier barr, Socket socket) {
    
    
        this.barr = barr;
        this.socket = socket;
    }

    @Override
    public void run() {
    
    
        boolean target = true;
        BufferedInputStream bis = null;
        while (target) {
    
    
            try {
    
    
                assert socket != null;
                if (socket.isConnected() && !socket.isClosed()) {
    
    
                    bis = getBufferedInputStream(socket);
                    byte[] tmp = new byte[1024];
                    int re;
                    while ((re = bis.read(tmp)) != -1) {
    
    
                        System.out.println(new String(tmp, 0, re));
                    }
                } else {
    
    
                    target = false;
                }
                Thread.sleep(1000 * 10);
            } catch (Exception e) {
    
    
                System.out.println("InThread = " + e.getMessage());
                target = false;
            } finally {
    
    
                try {
    
    
                    if (bis != null) {
    
    
                        bis.close();
                    }
                    if (socket != null) {
    
    
                        socket.close();
                    }
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }

        }
        try {
    
    
            barr.await();  // 第三次,等着
        } catch (InterruptedException | BrokenBarrierException e) {
    
    
            e.printStackTrace();
        }
    }

    private static BufferedInputStream getBufferedInputStream(Socket socket) {
    
    
        try {
    
    
            return new BufferedInputStream(socket.getInputStream());
        } catch (IOException e) {
    
    
            return null;
        }
    }

}

这里CyclicBarrier的详细使用详文末参考!这里简单提一下:

CyclicBarrier字面的中文意思是“循环栅栏[zhà lan]”,大概的意思就是一个可循环利用的屏障。它的作用就是会让所有线程都等待完成后才会继续下一步行动。

在这里插入图片描述

简化:

package top.onefine.test;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author one fine<br/>
 */
public class TCPDemo {
    
    

    public static final String HOST = "127.0.0.1";
    public static final int PORT = 11222;
    public static final int TIME_OUT = 30 * 1000;

    public static void main(String[] args) throws Exception {
    
    
        Socket socket;
        while (true) {
    
    
            CyclicBarrier barr = new CyclicBarrier(2);
            System.out.println("connecting to Server " + HOST + ":" + PORT);

            socket = initSocket();

            if (socket != null && socket.isConnected() && !socket.isClosed()) {
    
    
                System.out.println("connected...");

                InThread1 in = new InThread1(barr, socket);
                in.start();

                try {
    
    
                    barr.await();  // 第一次,等着
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }

            } else {
    
    
                System.out.println("connected failed, sleep for 10 s!");
                Thread.sleep(10 * 1000);
            }

            barr.reset();  // 重置
        }
    }

    private static Socket initSocket() {
    
    
        Socket socket;
        try {
    
    
            socket = new Socket();
            socket.connect(new InetSocketAddress(HOST, PORT), TIME_OUT);
        } catch (IOException e) {
    
    
            e.printStackTrace();  // java.net.ConnectException: Connection refused: connect
            return null;
        }
        return socket;
    }
}

class InThread1 extends Thread {
    
    
    private Socket socket;
    private CyclicBarrier barr;

    public InThread1(CyclicBarrier barr, Socket socket) {
    
    
        this.barr = barr;
        this.socket = socket;
    }

    @Override
    public void run() {
    
    
        boolean target = true;
        BufferedInputStream bis = null;
        while (target) {
    
    
            try {
    
    
                assert socket != null;
                if (socket.isConnected() && !socket.isClosed()) {
    
    
                    bis = getBufferedInputStream(socket);
                    byte[] tmp = new byte[1024];
                    int re;
                    while ((re = bis.read(tmp)) != -1) {
    
    
                        System.out.println(new String(tmp, 0, re));
                    }
                } else {
    
    
                    target = false;
                    System.out.println("连接断开...");
                }
                Thread.sleep(1000 * 10);

            } catch (Exception e) {
    
    
                System.out.println("InThread = " + e.getMessage());
                target = false;
            } finally {
    
    
                try {
    
    
                    if (bis != null) {
    
    
                        bis.close();
                    }
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }

        }


        try {
    
    
            barr.await();  // 第二次,等着
        } catch (InterruptedException | BrokenBarrierException e) {
    
    
            e.printStackTrace();
        }
    }

    private static BufferedInputStream getBufferedInputStream(Socket socket) {
    
    
        try {
    
    
            return new BufferedInputStream(socket.getInputStream());
        } catch (IOException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

}

注意:

在socket类中有一个方法sendUrgentData,它会往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节(在Java 中是抛出异常),而SO_OOBINLINE属性默认情况下就是关闭的。


参考:

深入理解CyclicBarrier原理 https://blog.csdn.net/qq_39241239/article/details/87030142

CyclicBarrier 使用详解 https://www.jianshu.com/p/333fd8faa56e

JAVA 判断Socket 远程端是否断开连接 https://www.cnblogs.com/wisdo/p/5859857.html

猜你喜欢

转载自blog.csdn.net/jiduochou963/article/details/107216365