zoukankan      html  css  js  c++  java
  • Java Socket通信实现私聊、群聊

     前言

      闲言少叙,上代码!

      代码编写

       server服务端

    /**
     * 服务端
     */
    public class Server {
        private static ServerSocket server = null;
        private static Socket ss = null;
        /**
         * 客户端集合
         */
        private static Map<String, ServerThread> serverThreadMap = new HashMap<String, ServerThread>();
    
    
        public static void main(String[] args) {
            server();
        }
    
        /**
         * 普通服务器连接
         */
        private static void server() {
            try {
                //建立服务端
                server = new ServerSocket(10010);
                System.out.println("server端已启动!");
                while (true) {
                    //创建接收接口
                    ss = server.accept();
                    //启动新客户监听线程
                    new ServerThread(server, ss).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    ss.close();
                    server.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 内部类线程,每连接一个新的客户端就启动一个对应的监听线程
         */
        @SuppressWarnings("Duplicates")
        private static class ServerThread extends Thread {
            ServerSocket server = null;
            Socket socket = null;
            InputStream is = null;
            OutputStream os = null;
            String clientName = null;
            boolean alive = true;
    
            public ServerThread() {
            }
    
            ServerThread(ServerSocket server, Socket socket) {
                this.socket = socket;
                this.server = server;
            }
    
            @Override
            public void run() {
                //接收数据
                try {
                    is = socket.getInputStream();
                    //发送
                    os = socket.getOutputStream();
                    //缓存区
                    byte[] b = new byte[1024];
                    int length = 0;
                    while (alive) {
                        //接收从客户端发送的消息
                        length = is.read(b);
                        if (length != -1) {
                            //文本消息
                            String message = new String(b, 0, length);
    
                            //JSON字符串转 HashMap
                            HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);
    
                            //消息类型
                            String type = (String) hashMap.get("type");
    
                            //新连接
                            if ("OPEN".equals(type)) {
                                clientName = (String) hashMap.get("clientName");
                                //添加客户端到集合容器中
                                serverThreadMap.put(clientName, this);
                                System.out.println(clientName + "连接成功!");
                                System.out.println("当前客户端数量:" + serverThreadMap.size());
                            }
    
                            //关闭
                            if ("CLOSE".equals(type)) {
                                alive = false;
                                System.err.println(clientName + "退出连接,关闭监听线程!");
                            }
    
                            //文本消息
                            if ("MESSAGE".equals(type)) {
                                String msg = (String) hashMap.get("message");
    
                                String chat = (String) hashMap.get("chat");
                                //群聊(广播)
                                if ("GROUP".equals(chat)) {
                                    //遍历容器,给容器中的每个对象转发消息
                                    for (ServerThread st : serverThreadMap.values()) {
                                        //向其他客户端发送数据
                                        if (st != this) {
                                            st.os.write(new String(b, 0, length).getBytes());
                                        }
                                    }
    
                                    //后台打印
                                    System.out.println(clientName + "向所有人说:" + msg);
                                }
                                //私聊
                                if ("PRIVATE".equals(chat)) {
                                    String to = (String) hashMap.get("to");
                                    serverThreadMap.get(to).os.write(new String(b, 0, length).getBytes());
                                    //后台打印
                                    System.out.println(clientName + "" + to + "说:" + msg);
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.err.println("" + clientName + "连接中断,被迫关闭监听线程!");
                } finally {
                    try {
                        serverThreadMap.remove(clientName);
                        System.out.println("当前客户端数量:" + serverThreadMap.size());
                        os.close();
                        is.close();
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }

    client客户端

    /**
     * 客户端
     */
    @SuppressWarnings("Duplicates")
    public class Client {
        private static String serverInetAddress = "127.0.0.1";
        private static int serverPort = 10010;
        private static Socket client = null;
        private static OutputStream os = null;
        private static InputStream is = null;
        private static String thisName;
        private static boolean alive = true;
    
        /**
         * 客户端连接服务器
         */
        @SuppressWarnings("unused")
        public static void open(String name) {
            try {
                thisName = name;
                InetAddress inetAddress = InetAddress.getLocalHost();
                //建立连接
                client = new Socket(serverInetAddress, serverPort);
                //数据流发送数据
                os = client.getOutputStream();
                sendMsg("{"type":"OPEN","clientName":"" + name + ""}");
                //数据流接收数据
                is = client.getInputStream();
                byte[] b = new byte[1024];
                int length = 0;
                while (alive) {
                    //接收从服务器发送回来的消息
                    length = is.read(b);
                    if (length != -1) {
                        onMsg(new String(b, 0, length));
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    //关流
                    os.close();
                    client.close();
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 关闭客户端
         */
        public static void close() {
            sendMsg("{"type":"CLOSE"}");
            alive = false;
        }
    
        /**
         * 发送消息
         */
        public static void sendMsg(String msg) {
            try {
                //调用发送
                os.write(msg.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 收到消息的回调
         */
        private static void onMsg(String message) {
            //JSON字符串转 HashMap
            HashMap hashMap = null;
            try {
                hashMap = new ObjectMapper().readValue(message, HashMap.class);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            String msg = (String) hashMap.get("message");
    
            String chat = (String) hashMap.get("chat");
    
            String from = (String) hashMap.get("from");
    
            String to = (String) hashMap.get("to");
    
            //群聊
            if ("GROUP".equals(chat)) {
                //后台打印
                System.out.println(thisName + "收到(" + to + ")群聊消息:" + msg);
            }
            //私聊
            if ("PRIVATE".equals(chat)) {
                //后台打印
                System.out.println(thisName + "收到(" + from + ")私聊消息:" + msg);
            }
        }
    
        /**
         * 获取thisName
         */
        public static String getThisName() {
            return thisName;
        }
    }

    controller模拟调用客户端

    @RequestMapping("/sendMsg/{chat}/{msg}")
        public void sendMsg(@PathVariable("chat") String chat, @PathVariable("msg") String msg) {
            if ("group".equals(chat.toLowerCase())) {
                //群聊
                Client.sendMsg("{"type":"MESSAGE","chat":"GROUP","from":""+Client.getThisName()+"","to":"群号:xxxx","message":"" + msg + ""}");
            } else {
                //私聊
                Client.sendMsg("{"type":"MESSAGE","chat":"PRIVATE","from":""+Client.getThisName()+"","to":"" + chat + "","message":"" + msg + ""}");
            }
        }
    
        @RequestMapping("/starClient/{name}")
        public void starClient(@PathVariable("name") String name) {
            Client.open(name);
        }
    
        @RequestMapping("/closeClient")
        public void closeClient() {
            Client.close();
        }

     效果展示

      一个服务端、两个客户端(两个不同的工程、模拟两个客户端),注意,要先启动服务端,再启动客户端!

      使用controller模拟启动两个客户端:

      http://localhost:10086/springboot/user/starClient/张三

      http://localhost:10087/starClient/李四

      张三发送群聊

      http://localhost:10086/springboot/user/sendMsg/group/大家好啊

     

      张三是发送者,server不再转发此消息给张三

     

      张三向李四发送私聊信息

      http://localhost:10086/springboot/user/sendMsg/李四/老表,你好啊

      张三是发送者,server不再转发此消息给张三

      李四回复张三私聊信息

       李四是发送者,server不再转发此消息给李四

      下线、掉线

      张三:http://localhost:10086/springboot/user/closeClient

      李四:直接终止客户端进程

      后记

      这个例子服务端每次有新的客户端连接进来,就启动一个线程去监听与此客户端的通信,当有大量客户端时就不适用了,而且涉及界面时,java socket不能主动给浏览器发送消息,界面聊天只能用轮询的方式实现,不好;多客户端、涉及有界面的聊天建议使用websocket(猛戳这里 -->WebSocket+Java 私聊、群聊实例)。

    版权声明

    作者:huanzi-qch
    若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
  • 相关阅读:
    【Linux高频命令专题(7)】rm
    【Linux高频命令专题(6)】mkdir
    【mongoDB运维篇①】用户管理
    【Linux高频命令专题(5)】rmdir
    【mongoDB中级篇②】索引与expain
    【mongoDB中级篇①】游标cursor
    Lua中的字符串函数库
    ngx_lua 随笔
    Nginx与Lua
    MAC 上搭建lua
  • 原文地址:https://www.cnblogs.com/Im-Victor/p/15157136.html
Copyright © 2011-2022 走看看