java socketio 入门Demo

WebSocket :一种通信协议 ,其作用建立一个连接通道,使数据交互从传统的请求响应的方式 改为了实时的双向推送 ,解决了 http 协议的部分不足

这里就直接整合了spring boot,spring boot 太香了

聊天demo代码(服务器版)

  1. 依赖(没贴spring boot的)
<dependency>
			<groupId>com.corundumstudio.socketio</groupId>
			<artifactId>netty-socketio</artifactId>
			<version>1.7.11</version>
		</dependency>
  1. 设置全局的配置对象
@Configuration
public class SocketConfig {

    private int PORT = 8081;

    private String HOST = "localhost";


    @Bean
    public SocketIOServer socketIOServer() {
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        //不设置主机、默认绑定0.0.0.0 or ::0
//        config.setHostname(WSS_HOST);
        config.setPort(PORT);
        //这里还可以认证很多设置 比如仓库什么的
        //身份验证
        config.setAuthorizationListener(handshakeData -> {
            //这里没有启用任何认证 直接返回为 true,可以在这里写用户认证的逻辑

            //http://localhost:8081?username=test&password=test
            //            //例如果使用上面的链接进行connect,可以使用如下代码获取用户密码信息
            //            //String username = data.getSingleUrlParam("username");
            //            //String password = data.getSingleUrlParam("password");

            return true;
        });
        final SocketIOServer server = new SocketIOServer(config);
        return server;
    }

    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
        return new SpringAnnotationScanner(socketServer);
    }
}
  1. 编写消息处理者
@Component
public class MessageHandler {
    private static final Logger log = LoggerFactory.getLogger(MessageHandler.class);
    //会话集合,用来存储所有的客户端信息
    private static final ConcurrentSkipListMap<String, ClientInfo> webSocketMap = new ConcurrentSkipListMap<>();
    //静态变量,用来记录当前在线连接数。(原子类、线程安全)
    private static AtomicInteger onlineCount = new AtomicInteger(0);
	//服务器全局对象 发送信息 就靠它了
    private final SocketIOServer server;

    @Autowired
    public MessageHandler(SocketIOServer server) {
        this.server = server;
    }

    /**
     * connect事件处理,当客户端发起连接时将调用,每次建立连接都会调用一次该方法
     *
     * @param client
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        // clientid 来自请求地址中
        String clientId = client.getHandshakeData().getSingleUrlParam("clientid");
        log.info("web socket连接:" + clientId);
        UUID session = client.getSessionId();
        ClientInfo si = webSocketMap.get(clientId);
        // 如果没有连接信息、则新建会话信息
        if (si == null) {
            si = new ClientInfo();
            si.setOnline(true);

            //在线数加1
            log.info("socket 建立新连接、sessionId:" + session + "、clientId:" + clientId + "、当前连接数:" + onlineCount.incrementAndGet());
        }
        // 更新客户端连接信息
        si.setLeastSignificantBits(session.getLeastSignificantBits());
        si.setMostSignificantBits(session.getMostSignificantBits());
        si.setLastConnectedTime(new Date());
        //将会话信息更新保存至集合中
        webSocketMap.put(clientId, si);


    }


    public void sendMessage(Object Message) {
        // 这个方法 会向所有的客户端 发送信息。 事件名为 message_event
        // 只有客户端有监听这个事件 就能接收到信息
        for (String clientId : webSocketMap.keySet()) {
            ClientInfo clientInfo = webSocketMap.get(clientId);
            System.out.printf("开始往客户端%s发送数据", clientId);
            UUID session = new UUID(clientInfo.getMostSignificantBits(), clientInfo.getLeastSignificantBits());
            server.getClient(session).sendEvent("message_event", Message);
        }
    }

    /**
     * 断开连接
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String clientId = client.getHandshakeData().getSingleUrlParam("clientid");
        webSocketMap.remove(clientId);
        //在线数减1
        log.info("socket 断开连接、sessionId:" + client.getSessionId() + "、clientId:" + clientId + "、当前连接数:" + onlineCount.decrementAndGet());
    }

    /**
     * 消息接收入口,当接收到消息后,查找发送目标客户端,并且向该客户端发送消息,且给自己发送消息
     *
     * @param client
     * @param request
     * @param data
     */

    // onEvnt 对某个事件进行监听 当客户端有触发这个事件时候 调用。这里是一个聊天的逻辑处理
    @OnEvent(value = "message_event")
    public void onEvent(SocketIOClient client, AckRequest request, MessageInfo data) {
        // MessageInfo 该对象 由客户端发送事件时候提供
        String targetClientId = data.getTargetClientId();
        ClientInfo clientInfo = webSocketMap.get(targetClientId);

        //如果目标在线 那么发送消息,如果不在线 就不进行处理
        if (clientInfo != null && clientInfo.isOnline()) {
            UUID target = new UUID(clientInfo.getMostSignificantBits(), clientInfo.getLeastSignificantBits());
            log.info("目标会话UUID:" + target);
            MessageInfo sendData = new MessageInfo();
            sendData.setSourceClientId(data.getSourceClientId());
            sendData.setTargetClientId(data.getTargetClientId());
            sendData.setMsg(data.getMsg());
            // 向当前会话发送信息
            client.sendEvent("message_event", sendData);
            // 向目标会话发送信息
            server.getClient(target).sendEvent("message_event", sendData);
        }
    }

    /**
     * socket会话信息
     * 下面是自定义的一些消息对象
     */

    @Data
    public class ClientInfo {
        private String clientId;
        private boolean isOnline;
        private long mostSignificantBits;
        private long leastSignificantBits;
        private Date lastConnectedTime;

    }

    /**
     * 消息对象
     */
    public static class MessageInfo {
        //源客户端id
        private String sourceClientId;
        //目标客户端id
        private String targetClientId;
        //消息内容
        private String msg;
        // get/set方法 ....


        public void setSourceClientId(String sourceClientId) {
            this.sourceClientId = sourceClientId;
        }

        public void setTargetClientId(String targetClientId) {
            this.targetClientId = targetClientId;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

        public String getSourceClientId() {
            return sourceClientId;
        }

        public String getTargetClientId() {
            return targetClientId;
        }

        public String getMsg() {
            return msg;
        }
    }
}

客户端代码

客户端1

<!DOCTYPE html>
<html>
<head lang="zh">
    <meta charset="utf-8"/>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <title>Demo Chat</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.js"></script>
    <!--moment js下载地址:http://momentjs.com/ -->
    <script src="moment.js"></script>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <style>
        body {padding: 20px;} #console {height: 400px;overflow: auto;} .username-msg {color: orange;} .connect-msg {color: green;}.disconnect-msg {color: red;}.send-msg {color: #888}
    </style>
    <script>
        var clientId = 'user1',targetId = 'user2';
        var socket = io.connect('http://localhost:8081?clientid=' + clientId);
        socket.on('connect', function () {
            showMsg('<span class="connect-msg">成功连接到服务器!</span>');
        });

        socket.on('message_event', function (data) {
            showMsg('<br /><span class="username-msg">' + new Date().getHours()+' '+new Date().getMinutes()+' '+new Date().getSeconds()+ '</span> ' + data);
        });
        socket.on('disconnect', function () {
            showMsg('<span class="disconnect-msg">服务已断开!</span>');
        });
        function sendDisconnect() {
            socket.disconnect();
        }
        function sendMessage() {
            var message = $('#msg').val();
            $('#msg').val('');
            var jsonObject = {
                sourceClientId: clientId,
                targetClientId: targetId,
                msg: message
            };
            socket.emit('message_event', jsonObject);
        }
        function showMsg(message) {
            // alert(message)
            // var currentTime = "<span class='time'>" + moment().startOf('hour').fromNow() + "</span>";
            // var element = $("<div>" + currentTime + "" + message + "</div>");
            $('#console').append(message);
        }
        $(document).keydown(function (e) {
            if (e.keyCode == 13) {
                $('#send').click();
            }
        });
    </script>
</head>
<body>
<h1>Netty-socket.io Demo</h1><br/>
<div id="console" class="well"></div>
<form class="well form-inline" onsubmit="return false;">
    <input id="msg" class="input-xlarge" type="text" placeholder="Type something..."/>  
    <button type="button" onClick="sendMessage()" class="btn" id="send">Send</button>  
    <button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button>
</form>
</body>
</html>

客户端2

<!DOCTYPE html>
<html>
<head lang="zh">
    <meta charset="utf-8"/>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <title>Demo Chat</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.js"></script>
    <!--moment js下载地址:http://momentjs.com/ -->
    <script src="moment.js"></script>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <style>
        body {padding: 20px;} #console {height: 400px;overflow: auto;} .username-msg {color: orange;} .connect-msg {color: green;}.disconnect-msg {color: red;}.send-msg {color: #888}
    </style>
    <script>
        var clientId = 'user2',targetId = 'user1';
        var socket = io.connect('http://localhost:8081?clientid=' + clientId);
        socket.on('connect', function () {
            showMsg('<span class="connect-msg">成功连接到服务器!</span>');
        });

        socket.on('message_event', function (data) {
            showMsg('<br /><span class="username-msg">' + new Date().getHours()+' '+new Date().getMinutes()+' '+new Date().getSeconds()+ '</span> ' + data);
        });
        socket.on('disconnect', function () {
            showMsg('<span class="disconnect-msg">服务已断开!</span>');
        });
        function sendDisconnect() {
            socket.disconnect();
        }
        function sendMessage() {
            var message = $('#msg').val();
            $('#msg').val('');
            var jsonObject = {
                sourceClientId: clientId,
                targetClientId: targetId,
                msg: message
            };
            socket.emit('message_event', jsonObject);
        }
        function showMsg(message) {
            // alert(message)
            // var currentTime = "<span class='time'>" + moment().startOf('hour').fromNow() + "</span>";
            // var element = $("<div>" + currentTime + "" + message + "</div>");
            $('#console').append(message);
        }
        $(document).keydown(function (e) {
            if (e.keyCode == 13) {
                $('#send').click();
            }
        });
    </script>
</head>
<body>
<h1>Netty-socket.io Demo</h1><br/>
<div id="console" class="well"></div>
<form class="well form-inline" onsubmit="return false;">
    <input id="msg" class="input-xlarge" type="text" placeholder="Type something..."/>  
    <button type="button" onClick="sendMessage()" class="btn" id="send">Send</button>  
    <button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button>
</form>
</body>
</html>

同时启动这个两个就能进行聊天了