WebSocket 基本操作

168 阅读2分钟

概念

基于TCP的一种网络协议,一次握手就能实现双向连接

对比

httpwebscoket
HTTP 连接每次请求都需要建立连接,效率较低连接一旦建立,通信双方之间可以持久化,不需要每次请求都重新建立链接
HTTP 是单向的,只能由客户端发起请求,服务器响应请求双向实时通信
通信数据格式比 HTTP 更轻量级、更高效,可以大大减少通信数据量

实际上,WebSocket 已经被广泛应用在了很多实时通信的场景中,比如在线游戏、股票行情、即时通讯等领域。但是由于 WebSocket 的使用需要客户端和服务器端的支持,而传统的 HTTP 服务端架构很多并没有开放 WebSocket 的支持,所以在一些传统的应用场景下,如网站访问、文本通信等仍然使用 HTTP 协议。

此外,由于 WebSocket 建立连接后可以持久性通信,因此需要应用开发者考虑一些安全问题,比如连接的管理、保证连接的安全性等等。WebSocket 对于移动端数据使用的费用较高,也限制了 WebSocket 在移动场景下的应用。这些因素都限制了 WebSocket 的大规模应用。不过随着技术的发展和应用场景的变化,WebSocket已经成为了一个越来越重要的通信协议。

代码实现

导入依赖

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-websocket</artifactId>  
</dependency>

导入工具类

/**  
* WebSocket服务  
*/  
@Component  
@ServerEndpoint("/ws/{sid}")  
public class WebSocketServer {  

    //存放会话对象  
    private static Map<String, Session> sessionMap = new HashMap();  

    /**  
    * 连接建立成功调用的方法  
    */  
    @OnOpen  
    public void onOpen(Session session, @PathParam("sid") String sid) {  
        System.out.println("客户端:" + sid + "建立连接");  
        sessionMap.put(sid, session);  
    }  

    /**  
    * 收到客户端消息后调用的方法  
    *  
    * @param message 客户端发送过来的消息  
    */  
    @OnMessage  
    public void onMessage(String message, @PathParam("sid") String sid) {  
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);  
    }  

    /**  
    * 连接关闭调用的方法  
    *  
    * @param sid  
    */  
    @OnClose  
    public void onClose(@PathParam("sid") String sid) {  
        System.out.println("连接断开:" + sid);  
        sessionMap.remove(sid);  
    }  

    /**  
    * 群发  
    *  
    * @param message  
    */  
    public void sendToAllClient(String message) {  
        Collection<Session> sessions = sessionMap.values();  
        for (Session session : sessions) {  
            try {  
            //服务器向客户端发送消息  
                session.getBasicRemote().sendText(message);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}

注册组件

/**  
* WebSocket配置类,用于注册WebSocket的Bean  
*/  
@Configuration  
public class WebSocketConfiguration {  
  
    @Bean  
    public ServerEndpointExporter serverEndpointExporter() {  
        return new ServerEndpointExporter();  
    }  
  
}

定时任务类

通过WebSocket每隔5秒向客户端发送消息

@Component  
public class WebSocketTask {  
    @Autowired  
    private WebSocketServer webSocketServer;  

    /**  
    * 通过WebSocket每隔5秒向客户端发送消息  
    */  
    @Scheduled(cron = "0/5 * * * * ?")  
    public void sendMessageToClient() {  
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));  
    }  
}

客户端

连接服务器并发送消息

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Demo</title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <button onclick="closeWebSocket()">关闭连接</button>
    <div id="message">
    </div>
</body>
<script type="text/javascript">
    var websocket = null;
    var clientId = Math.random().toString(36).substr(2);

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
    }
    else{
        alert('Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };

    //连接成功建立的回调方法
    websocket.onopen = function(){
        setMessageInnerHTML("连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
	
	//关闭连接
    function closeWebSocket() {
        websocket.close();
    }
</script>
</html>

nginx相关配置(如果需要)

upstream webservers{
  server 127.0.0.1:8080 weight=90 ;
  #server 127.0.0.1:8088 weight=10 ;
}

# WebSocket
location /ws/ {
    proxy_pass   http://webservers/ws/;
    proxy_http_version 1.1;
    proxy_read_timeout 3600s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "$connection_upgrade";
}

参考

更多可参考:blog.csdn.net/qq_15752347…