美文网首页
WebSocket原理

WebSocket原理

作者: 坤坤坤坤杨 | 来源:发表于2022-12-05 12:59 被阅读0次

    WebSocket是应用层上的一个应用层协议,持久化的协议,他必须依赖http协议进行一次握手,成功后就直接从tcp通道传输,后续就与http无关了。

    WebSocket是以frame形式传输数据的,比如会将一条消息分为多个frame,按照先后顺序传输出去,他的好处有以下几点:

    1. 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志不足的请求。
    2. 和http的chunk一样,可以一边产生数据,一边传递数据,即提高传输效率。

    1. 特点

    1. 长连接。
    2. 主要是服务端给客户端发送数据。
    3. WebSocket使用时浏览器与服务端最开始建立的还是http连接,之后再将协议转换为ws,在请求头上增加额外信息 upgrade:webSocket,connection:upgrade,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
      GET /chat HTTP/1.1
      Host: server.example.com
      Upgrade: websocket
      Connection: Upgrade
      Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==  //是一个 Base64 encode 的值,这个是浏览器随机生成的
      Sec-WebSocket-Protocol: chat, superchat //是一个用户定义的字符串,用来区分同 URL 下,不同的服务所需要的协议
      Sec-WebSocket-Version: 13 //告诉服务器所使用的 WebSocket Draft (协议版本)
      Origin: http://example.com
      
    4. 端口与http协议一样,默认80,wss和https一样,默认443
    5. 减少了http长轮询造成的资源浪费,解决了不能由服务端向客户端主动推送的问题,提高了实时性。
    6. 数据格式比较轻量,性能开销小,通信高效。
    7. 可以发送文本,也可以发送二进制数据。
    8. 没有同源限制,客户端可以与任意服务器通信。
    9. 建立在 TCP 协议之上,服务器端的实现比较容易。

    2. 在WebSocket之前,web上实现实时数据交互的方式

    1. 定期轮询:客户端按照某个时间间隔不断地向服务器发送请求,请求服务端的最新数据然后更新数据到客户端显示,这种方式浪费了大量的流量,并且对服务端造成了很大的压力。
    2. 基于长轮询的服务端推送技术:客户端首先给服务端发送一个请求,服务端收到该请求之后如果数据没有更新则并不立刻返回,服务端会阻塞请求的放回,直到数据发生了更新或者发生了连接超时,服务端返回数据之后客户端再次发送同样的请求。

    3. 服务端代码实现(tomcat)

    package com.scoket.scoketTest;
    
    
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    
    /**
     * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
     * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
     */
    @ServerEndpoint("/websocket")
    public class WebSocketTest {
        //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
        private static int onlineCount = 0;
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
        private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
    
        //与某个客户端的连接会话,需要通过它来给客户端发送数据
        private Session session;
    
        /**
         * 连接建立成功调用的方法
         * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
         */
        @OnOpen
        public void onOpen(Session session){
            this.session = session;
            webSocketSet.add(this);     //加入set中
            addOnlineCount();           //在线数加1
            System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose(){
            webSocketSet.remove(this);  //从set中删除
            subOnlineCount();           //在线数减1
            System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 收到客户端消息后调用的方法
         * @param message 客户端发送过来的消息
         * @param session 可选的参数
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println("来自客户端的消息:" + message);
            //群发消息
            for(WebSocketTest item: webSocketSet){
                try {
                    item.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    
        /**
         * 发生错误时调用
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error){
            System.out.println("发生错误");
            error.printStackTrace();
        }
    
        /**
         * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
         * @param message
         * @throws IOException
         */
        public void sendMessage(String message) throws IOException{
            this.session.getBasicRemote().sendText(message);
            //this.session.getAsyncRemote().sendText(message);
        }
    
        public static synchronized int getOnlineCount() {
            return onlineCount;
        }
    
        public static synchronized void addOnlineCount() {
            WebSocketTest.onlineCount++;
        }
    
        public static synchronized void subOnlineCount() {
            WebSocketTest.onlineCount--;
        }
    }
    

    相关文章

      网友评论

          本文标题:WebSocket原理

          本文链接:https://www.haomeiwen.com/subject/xdtifdtx.html