Java使用Socket实现服务器与客户端通信

        最近在写一个Android 网络局域网通信功能,客户端将数据发送到服务器后,服务器再将这个数据转发给其他客户端为了方便起见,写了一个工具类,废话不多说,上代码,这段代码是基于Gson 的,需要在Android文件build.gradle 中引用。

 //Gson
    implementation 'com.google.code.gson:gson:2.8.0'

思路解析:

先使用Socket连接,获取异常,判断是否存在这个服务器是否可以连接

 try {
      Socket socket = new Socket(host, port);
      SocketNode node = SocketNode.getNode(socket);
      if(node != null){
           return new SocketManager(node);
      }else{
          return null;
      }

} catch (IOException e) {}

如果没有被连接,就创建一个新的ServerSocket 再通过线程去不断读取数据

虽然这个连接不是很安全,最好还是用加密方式将数据进行加密。

全部代码:


/**
 * Socket 通信控制
 * @author Sobadfish
 *
 * */
public class SocketManager {


    // 线程池管理
    public static ExecutorService executor = Executors.newCachedThreadPool() ;

    private SocketNode socket;

    /*
    是否为启动状态
    * */
    public boolean enable;

    /**
     * 服务端IP
     * */
    public String host;

    /**
     * 服务端端口
     * */
    public int hostPort;

    /**
     * 主机分配的端口
     * */
    private static int port = -1;

    private final SocketType type;

    private SocketDataListener dataListener;

    private SocketConnectListener connectListener;

    private ServerSocket serverSocket;

    private List sockets = new CopyOnWriteArrayList<>();

    private SocketManager(SocketNode socket){
        this.socket = socket;
        host = socket.ip;
        hostPort = socket.port;
        type = SocketType.SOCKET;
        enable = true;
        connect();

    }


    private SocketManager(ServerSocket serverSocket){
        this.serverSocket = serverSocket;
        this.sockets = new CopyOnWriteArrayList<>();
        port = serverSocket.getLocalPort();
        hostPort = socket.port;
        type = SocketType.SERVER;
        enable = true;
        enable();

        connect();


    }

    public SocketType getType() {
        return type;
    }

    /**
     * 绑定数据监听 网络通信中获取到的数据将通过监听事件发送
     * @param listener 事件监听
     * */
    public void setDataListener(SocketDataListener listener) {
        this.dataListener = listener;
    }

    /**
     * 建立服务端与客户端的通信 如果服务端不存在,则创建服务端
     *
     * @param host 服务器IP
     * @param port 服务器端口
     * */
    public static SocketManager connectManager(String host, int port){
        try {
            Socket socket = new Socket(host, port);
            SocketNode node = SocketNode.getNode(socket);
            if(node != null){
                return new SocketManager(node);
            }else{
                return null;
            }

        } catch (Exception e) {
            // 不存在服务器
            System.out.println("不存在服务主机 或 主机无法连接 " + host + " 正在创建端口 " + port + " 的主机");
            try {
                ServerSocket serverSocket = new ServerSocket(port);
                return new SocketManager(serverSocket);
            } catch (IOException ioException) {

                System.out.println("创建失败 " + ioException.getMessage());

            }

        }
        return null;
    }

    /**
     * 绑定连接事件监听
     * 当有 Socket 连接的时候会通过这个事件回调
     *
     * @param listener 监听器
     * */
    public void setConnectListener(SocketConnectListener listener) {
        this.connectListener = listener;
    }

    /**
     * 向网络中发送数据
     * @param messageData 监听器
     * */
    public boolean sendMessage(MessageData messageData){
        switch (type){
            case SOCKET:
                if(socket != null && port > 0){
                    // 通信建立后才行发送数据
                    return socket.sendMessage(messageData);

                }
                break;
            case SERVER:
                if(sockets.size() > 0) {
                    for (SocketNode node : sockets) {
                        if(!node.sendMessage(messageData)){
                            if (connectListener != null) {
                                connectListener.quit(node);
                                sockets.remove(node);
                            }

                        }
                    }
                    return true;
                }
                break;
            default:break;
        }
        return false;
    }

    private void enable() {
        executor.execute(() -> {
            Socket socket = null;
            while (serverSocket != null && !serverSocket.isClosed()){
                try {
                    socket = serverSocket.accept();
                    SocketNode node = SocketNode.getNode(socket);
                    if(node != null){
                        sockets.add(node);
                        // 回传分配的端口
                        node.sendMessage(MessageData.createMessage(new PortBack(node.port)));
                        if(connectListener != null){
                            connectListener.join(node);
                        }
                    }
                } catch (IOException e) {

                    if(socket != null){
                        System.out.println(socket.getInetAddress()+":"+socket.getPort()+"断开连接");
                    }

                }
            }
        });
    }


    /**
     *
     * 数据通信类
     * 用于向网络发送数据
     * */
    public static class MessageData{

        public String host;

        public String name;

        public int port;

        public String msg;

        public Long time;


        public static MessageData createMessage(Object o){
            MessageData data = new MessageData();
            try {
                InetAddress addr = InetAddress.getLocalHost();
                data.host = addr.getHostAddress();

            } catch (UnknownHostException e) {
                data.host =  "Unknown Host";
            }
            data.name = addr.getHostAddress();
            data.time = System.currentTimeMillis();
            Gson gson = new Gson();
            data.msg = gson.toJson(o);
            return data;
        }

        public  T getData(Class data){
            Gson gson = new Gson();
            return gson.fromJson(msg,data);
        }

        @Override
        public String toString() {
            Gson gson = new Gson();
            return gson.toJson(this);
        }
    }



    public static class PortBack{
        public int port;
        public PortBack(int port){
            this.port = port;
        }

        public int getPort() {
            return port;
        }
    }




    private void connect() {
        executor.execute(() -> {
            while (isEnable()) {
                if (type == SocketType.SERVER) {
                    // 遍历时修改
                    for (SocketNode node : sockets) {
                        if (node != null && node.isConnected()) {
                            if(node.isEnable()){
                                if(!node.isInit) {
                                    if (!node.read(this)) {
                                        if (connectListener != null) {
                                            connectListener.quit(node);
                                            sockets.remove(node);
                                        }
                                        node.disable();
                                    }
                                }
                            }
                        }
                    }
                }
                if (type == SocketType.SOCKET) {
                    if (socket != null && socket.isConnected()) {
//                        read(socket.socket);
                        if(socket.isEnable()){
                            if(!socket.isInit){
                                if(!socket.read(this)){
                                    if(connectListener != null){
                                        connectListener.quit(socket);
                                    }
                                    socket.disable();

                                }
                            }

                        }
                    }
                }
            }
            //断开连接 尝试查找服务器..
            if (type == SocketType.SOCKET) {
                //10 s 重连一次
                try {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    socket = SocketNode.getNode(new Socket(host, hostPort));

                    connect();
                } catch (IOException ignore) {
                }



            }



        });
    }


    /**
     * 判断连接是否有效
     *
     * */
    public boolean isEnable(){
        if(enable) {
            switch (type) {
                case SERVER:
                    if (serverSocket != null) {
                        return !serverSocket.isClosed();
                    }
                    break;
                case SOCKET:
                    if (socket != null) {
                        return socket.isConnected();
                    }
                    break;
                default:
                    break;
            }
        }
        return false;
    }

    public enum SocketType{
        /**
         * 类型为主机*/
        SERVER,
        /**
         * 类型为客户端*/
        SOCKET
    }

    public interface SocketDataListener{

        void handleMessage(SocketManager socketManager,MessageData messageData);
    }

    public interface SocketConnectListener{

        void join(SocketNode socket);

        void quit(SocketNode socket);
    }

    public void sendMessage(Object o){
        MessageData messageData = MessageData.createMessage(o);
        if(!sendMessage(messageData)){
            System.out.println(o.toString()+" 消息发送失败!");
        }

    }


    public static class SocketNode{

        private Socket socket;

        private final String ip;

        private boolean isInit = false;

        private boolean enable;

        private final int port;

        public String getIPAddress(){
            return ip;
        }

        public int getPort() {
            return port;
        }

        private SocketNode(Socket socket){
            this.socket = socket;
            enable = true;
            if(socket != null && socket.isConnected()){
                ip = socket.getInetAddress().getHostAddress();
                port =  socket.getPort();
                try {
                    inputStream = socket.getInputStream();
                    outputStream = socket.getOutputStream();
                } catch (IOException e) {
                    inputStream = null;
                    outputStream = null;
                }
            }else{
                ip = "Unknown";
                port = -1;
            }


        }

        public boolean isEnable() {
            return enable;
        }

        public void disable(){
            enable = false;
            if(socket != null){
                try {
                    socket.close();

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            socket = null;
        }

        public boolean read(SocketManager manager){

            if(!isInit) {
                isInit = true;
                if (inputStream == null) {
                    return false;
                }
                executor.execute(new NodeReadRunnable(this,manager));
            }

            return true;


        }

        private static class NodeReadRunnable implements Runnable{

            public SocketNode node;

            public SocketManager manager;

            public NodeReadRunnable(SocketNode socketNode,SocketManager manager){
                this.node = socketNode;
                this.manager = manager;
            }
            @Override
            public void run() {
                Gson gson = new Gson();
                Socket socket = node.socket;
                InputStream inputStream = node.inputStream;
                while (!socket.isClosed()) {
                    try {
                        byte[] bytes = new byte[1024];
                        inputStream.read(bytes, 0, bytes.length);
                        String out = new String(bytes, StandardCharsets.UTF_8).trim();
                        if (!"".equalsIgnoreCase(out.trim())) {
                            MessageData data = gson.fromJson(out, MessageData.class);
                            PortBack portBack = data.getData(PortBack.class);
                            if (portBack != null && portBack.port > 0) {
                                SocketManager.port = portBack.port;
                                if (manager.connectListener != null) {
                                    manager.connectListener.join(node);
                                }
                            } else {
                                portBack = null;
                            }
                            // 判断是否为主机 如果是主机就把收到的数据分发给其他客户端
                            if (manager.type == SocketType.SERVER) {
                                for (SocketNode node : manager.sockets) {
                                    // 别再把数据又发回去了,这不就重复了吗
                                    //当然你也可以选择重复,只在接收区显示
                                    //增加这个判断是为了 忽略发送数据到服务器的客户端
                                    if (node.equals(this.node)) {
                                        continue;
                                    }
                                    node.sendMessage(data);
                                }
                            }
                            if (manager.dataListener != null) {
                                if (portBack != null) {
                                    continue;
                                }
                                manager.dataListener.handleMessage(manager, data);
                            }

                        }

                    } catch (Exception e) {
                        return;
                    }

                }
                // 进入这个判断后说明连接被关闭了
                if (manager.type == SocketType.SERVER) {
                    if (manager.connectListener != null) {
                        manager.connectListener.quit(node);
                    }
                }
            }
        }


        public static SocketNode getNode(Socket socket){
            if(socket.isConnected()){
                return new SocketNode(socket);
            }
            return null;
        }


        public boolean isConnected() {
            return socket != null && socket.isConnected();
        }

        private boolean sendMessage(MessageData messageData){
            if(isConnected()) {
                messageData.port = port;
                Gson gson = new Gson();
                byte[] msg = gson.toJson(messageData).getBytes(StandardCharsets.UTF_8);
                try {
                    if(outputStream != null){
                        outputStream.write(msg);
                        outputStream.flush();
                    }
                } catch (IOException e) {
                    disable();
                    return false;

                }
            }
            return true;

        }

        private InputStream inputStream;

        private OutputStream outputStream;



        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            SocketNode node = (SocketNode) o;
            return Objects.equals(socket, node.socket);
        }

        @Override
        public int hashCode() {
            return Objects.hash(socket);
        }
    }

    public void disable(){
        enable = false;
        if(serverSocket != null){
            try {
                serverSocket.close();
                serverSocket = null;
                sockets.clear();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(socket != null){
            try {
                socket.socket.close();
                socket = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


}

 使用方法:

SocketManager manager = SocketManager.connectManager("你要连接的服务器IP","你要连接的服务器端口");
//获取传输的数据
manager.setDataListener(new SocketManager.SocketDataListener() {
        @Override
        public void handleMessage(SocketManager socketManager, SocketManager.MessageData messageData) {
//接收到的数据
                    
        }
);

//客户端连接/断开服务器监听
 manager.setConnectListener(new SocketManager.SocketConnectListener() {
        @Override
        public void join(SocketManager.SocketNode socket) {
                   //客户端连接
        
        }
        @Override
        public void quit(SocketManager.SocketNode socket) {
                   //客户端断开
        }

        
 });

连接出现的问题

建立连接后,当节点断开,主机这边会有一个关于List的报错,是因为在删除的时候又遍历节点去获取内容,将保存的节点数组改为

private List sockets = new CopyOnWriteArrayList<>();

就可以解决那个问题了。

问题2:

在传送字符串的时候会出现乱码情况,所以在这里我使用了Base64进行编码解码,统一编码为UTF-8 就可以解决乱码问题

你可能感兴趣的:(java,android)