Socket通讯

实现一台主机(相当于服务器Server) 多台副机(Client)之间相互通讯

 1 Client 思考问题  长连接
      如何保活(心跳线程 每隔1分钟发送一个心跳包到Server端 最后一次记录心跳的时间 根据心跳时间来判断线程是否存活)

 2 Server 如何处理链路问题(轮询去除已经断开连接的副机子)   

     开启一个子线程 每隔6分钟检测一次 如果和副机子断开连接了 从缓存中去除掉副机

 实现Server端

  1 ServerSocket监听指定的端口

try {
    ServerSocket serverSocket = new ServerSocket();
    serverSocket.setReuseAddress(true);
    serverSocket.bind(new InetSocketAddress(port));
    Log.d("server", "   port---->" + port);
    while (!callFinish) {
        Log.d("server", "server runing");
        Socket socket = serverSocket.accept();
        receiveClient(socket);
    }
} catch (IOException e) {
    e.printStackTrace();
}

  2 Server处理链路问题 移除已经失效的Client客户端

private void initClientCheck() {

    if (handlerThread == null) {
        handlerThread = new HandlerThread("ALPServerLoop") {

            @Override
            public void run() {
                super.run();

                while (!callFinish) {

                    try {
                        //Thread.sleep(6 * 60 * 1000);
                        Thread.sleep(10 * 1000);
                        Log.d("server", "server 链路每过10秒检查一次");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    List<ClientHandler> clientHandlers = new ArrayList<>();
                    clientHandlers.addAll(clientList);
                    for (ClientHandler clientHandler : clientHandlers) {

                        //客户端终止了 或者心跳时间超过6分钟
                        if (clientHandler.isFinish) {
                            Log.d("server", "server检测到 客户端断开连接了 ");
                            clientHandler.callStop();
                            synchronized (Server.this) {
                                Log.d("server", "server检测到 客户端断开连接了 移除客户端 --->" + clientHandler.getName());
                                clientList.remove(clientHandler);
                            }

                        }

                    }
                }


            }
        };
        handlerThread.start();
    }

}

Server完整代码

public class Server {


    /**
     * 客户端列表
     */
    private List<ClientHandler> clientList = new ArrayList<>();

    /**
     * 手动终止服务
     * 包括终止该服务所有的子线程
     */
    private boolean callFinish = false;


    protected Server() {

    }

    public void init(int port) {

        initClientCheck();

        try {
            ServerSocket serverSocket = new ServerSocket();
            serverSocket.setReuseAddress(true);
            serverSocket.bind(new InetSocketAddress(port));
            Log.d("server", "   port---->" + port);
            while (!callFinish) {
                Log.d("server", "server runing");
                Socket socket = serverSocket.accept();
                receiveClient(socket);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 链路检查
     * 1 移除已经断开连接的副机子
     * 2 移除6分钟没有收到心跳包的副机子(副机子没1分钟保持一次心跳)
     */
    private HandlerThread handlerThread;

    private void initClientCheck() {

        if (handlerThread == null) {
            handlerThread = new HandlerThread("ALPServerLoop") {

                @Override
                public void run() {
                    super.run();

                    while (!callFinish) {

                        try {
                            //Thread.sleep(6 * 60 * 1000);
                            Thread.sleep(10 * 1000);
                            Log.d("server", "server 链路每过10秒检查一次");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        List<ClientHandler> clientHandlers = new ArrayList<>();
                        clientHandlers.addAll(clientList);
                        for (ClientHandler clientHandler : clientHandlers) {

                            //客户端终止了 或者心跳时间超过6分钟
                            if (clientHandler.isFinish) {
                                Log.d("server", "server检测到 客户端断开连接了 ");
                                clientHandler.callStop();
                                synchronized (Server.this) {
                                    Log.d("server", "server检测到 客户端断开连接了 移除客户端 --->" + clientHandler.getName());
                                    clientList.remove(clientHandler);
                                }

                            }

                        }
                    }


                }
            };
            handlerThread.start();
        }

    }


    /**
     * 收到链路创建的请求
     *
     * @param client Socket
     */
    private void receiveClient(Socket client) {

        Log.d("server", "Server receiveClient " + String.format("开始监听客户端: %s", client.getRemoteSocketAddress()));

        ClientHandler clientHandler = new ClientHandler(client);
        synchronized (Server.this) {
            Log.d("server", "ClientHandler created " + clientHandler.getName());
            clientList.add(clientHandler);
        }
        clientHandler.setName("ClientHandler" + client.getInetAddress());
        clientHandler.start();
        //clientHandler.lastBeating = SystemClock.elapsedRealtime();
    }


    //相当于Client  只是继承了Thread 实现什么功能呢
    private class ClientHandler extends Thread {

        private Socket socket;

        private InputStream inputStream;

        private OutputStream outputStream;

        private boolean callStop = false;

        private boolean isFinish = false;


        public ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            super.run();
            init();

            while (!callStop) {

                try {
                    if (inputStream == null) {
                        break;
                    }
                    int len = 0;
                    byte[] bytes = new byte[inputStream.available()];
                    while ((len = inputStream.read(bytes)) != -1) {
                        Log.d("server", new String(bytes));
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            Log.d("server","ClientHandler 断开连接了 ");
            isFinish = true;

        }


        private void init() {

            try {
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


        private void pushMsg(String msg) {

            try {
                byte[] bytesInfo = msg.getBytes();
                if (outputStream != null) {
                    Log.d("server", "server write msg -->" + msg);
                    outputStream.write(bytesInfo);
                    outputStream.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
                callStop();
            }

        }

        public void callStop() {

            try {
                if (inputStream != null) {
                    inputStream.close();
                }

                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            inputStream = null;
            outputStream = null;

            callStop = true;
            isFinish = true;

        }


    }


    /**
     * 服务器推送消息到客户端
     *
     * @param msg
     */
    public void pushMsgToAll(String msg) {

        for (ClientHandler clientHandler : clientList) {
            clientHandler.pushMsg(msg);
        }

    }


    /**
     * 结束掉当前的服务器
     */
    public void finish() {

        clientList.clear();
        //keyClient.clear();
        callFinish = true;
    }


}


2 PushServer 对Server进一步封装

public class PushServer {

    private Server server;
    private Thread workingThread;

    public static PushServer pushServer = new PushServer();


    private PushServer() {
        init();
    }

    private Handler pushServerHandler = null;

    private void init() {

        HandlerThread thread = new HandlerThread("ClientHeartBeatingThread") {
            @Override
            protected void onLooperPrepared() {
                super.onLooperPrepared();
                pushServerHandler = new Handler(Looper.myLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                    }
                };

            }
        };
        thread.start();

    }


    public void startServer(final int port) {

        workingThread = new Thread(new Runnable() {
            @Override
            public void run() {

                Log.d("pushServer", "开启Server");
                server = new Server();
                server.init(port);

            }
        });
        workingThread.setName("PushServerWorking");
        workingThread.start();

    }


    /**
     * 推送消息到所有站点
     *
     * @param msg String | 消息体
     */
    public void pushMsg(final String msg) {

        pushServerHandler.post(new Runnable() {
            @Override
            public void run() {
                if (server == null) {
                    return;
                }
                server.pushMsgToAll(msg);
            }
        });
    }


    public void finishServer() {
        if (server != null) {
            Log.d("pushServer", "server finish");
            server.finish();
        }
        try {
            if (workingThread != null && workingThread.isInterrupted() && workingThread.isAlive()) {
                Log.d("pushServer", "workingThread interrupt" + workingThread.getName());
                workingThread.interrupt();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}


3 Client实现 

客户端开始连接 注意点 Client和Server端在同一个网端下 并且监听的是同一个端口 startConnect里面开启了一个死循环一直等待读取Server反馈的信息

/**
 * 客户端开始连接
 * @param address
 * @param port
 */
public void startConnect(String address, int port) {

    try {
        socket = new Socket();
        socket.connect(new InetSocketAddress(address, port), 3000);
        socket.setKeepAlive(true);
        inputStream = socket.getInputStream();
        outputStream = socket.getOutputStream();

        while (!callFinish){
           read();
        }
        Log.d("clinet","address--->"+address+  "   port---->" +port);

    } catch (IOException e) {
        e.printStackTrace();
    }

}


4 pushClient 对Client进一步封装 实现心跳包保活机制 实现网络监听 后期实现该功能


public class PushClient {

    String address;
    int port;
    private Client client;

    public void startClient(String address, int port) {
        this.address = address;
        this.port = port;
        connect();
    }

    public void connect() {

        disConnect();
        Thread workingThread = new Thread(new Runnable() {
            @Override
            public void run() {

                client = new Client();
                client.startConnect(address, port);
            }
        });
        workingThread.setName("PushClientWorking_" + System.currentTimeMillis());
        workingThread.start();

    }

    /**
     * 断开本地的Socket连接
     */
    private synchronized void disConnect() {
        if (client != null) {
            client.close();
        }
    }


    /**
     * 推送消息到服务器
     * @param msg
     */
    public void pushMsg(String msg) {

        if (client != null) {
            client.pushMsgToServer(msg);
        }

    }


}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值