体验了一把websocket

WebSocket是个啥

态度明确点,这玩意儿是个协议。
从http1.1相较于http1.0增加的功能之一就是长连接(Persistent Connection),作用就是为了弥补http无法长时间保持活性的缺点,让以前只能通过轮询实现的功能看起来优雅一点。好嘛,原理上支持了之后,我这http里没有对应的协议咋办。WebSocket就来了。

WebSocket有啥特点

直接上图
体验了一把websocket
相较于http请求多了几个东西:

Upgrade: websocket
Connection: Upgrade

请求用这俩告诉服务器,老子是websocket请求,你注意点,别给我割断喽。

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: pHl+HeJx5QV8NZuTw0xtYQ==
Sec-WebSocket-Version: 13

服务器:出示一下你的key以及您需要的服务类型Extensions,哦哦您是一三版的,欢迎欢迎~

Sec-WebSocket-Accept: iKC4KsGSKf4cna4SdMVX0rmjQik=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Upgrade: websocket

服务器:这是您今晚的身份卡请收好,这边请。

WebSocket的作用

websocket常用于实现数据更新的实时通知的业务场景。区别于ajax轮询,websocket只需要一次握手便能与服务器建立链接,而且信息由服务器端推送通知。

WebSocket代码实现

前端(vue组件):

<script>
const df = function (ms) {return function (e) {console.log(`webSocket---${ms}---webSocket---${e.data || ""}`)}}
export default {
  name:"webConnection",
  props:{
    url:{
      default:"",
      type:String
    },
    onopen:{
      default:df('开始链接'),
      type:Function
    },
    onmessage:{
      default:df('收到消息'),
      type:Function
    },
    onclose:{
      default:df('关闭'),
      type:Function
    },
    one rror:{
      default:df('发生错误'),
      type:Function
    }
  },
  data() {
    return {
      socket:null
    }
  },
  computed:{
    WebSocketUrl:function() {
      let url = "";
      this.url.includes('https') ? 
      url = this.url.replace(new RegExp(/https/),'wss') : 
      url = this.url.replace(new RegExp(/http/),'ws') ;
      return url;
    }
  },
  methods:{
    Connect() {
      if(typeof(WebSocket) === "undefined") return;
      try {
        this.socket = new WebSocket(this.WebSocketUrl);
        this.socket.onopen = this.onopen;
        this.socket.onmessage = this.onmessage;
        this.socket.onclose = this.onclose;
        this.socket.onerror = this.onerror;
        console.log('连接成功');
      } catch(err) {
        console.log('连接失败');
      }
    },
    sendMsg(msg) {
      if(this.socket && this.socket.readyState === 1) {
        this.socket.send(msg);
      } else {
        alert('暂无链接存在,请先建立连接')
      }
    },
    reConnect() {
      if(this.socket && this.socket.readyState === 1) {
        this.disConnect();
      }
      this.Connect();
    },
    destoryConnect() {
      this.disConnect();
      this.socket = null;
    },
    disConnect() {
      if(this.socket && this.socket.readyState !== 3) {
        this.socket.close();
      }
    }
  },
  mounted() {
    this.Connect();
  },
  render() {},
  beforeDestroy() {
    this.destoryConnect();
  }
}
</script>

后端:

配置类

public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }

链接层

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;



import org.springframework.stereotype.Component;

//@ServerEndpoint("/websocket/{user}")
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this); //加入set中
        addOnlineCount(); //在线数加1

        try {
            sendMessage("连接成功");
        } catch (IOException e) {

        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this); //从set中删除
        subOnlineCount(); //在线数减1

    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void one rror(Session session, Throwable error) {

        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 群发自定义消息
     * */
    public static void sendInfo(String message) throws IOException {

        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}

接口层

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;

import com.xzs1.first.service.WebSocketServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value="/websocket")
public class webscoket {

    @RequestMapping(value="/sendToOne", produces = {"application/json; charset=utf-8"},method=RequestMethod.POST)
    public void sendToOne(HttpServletRequest request,String message){
        String str = message;
        try {
            WebSocketServer.sendInfo(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实现效果

(手动藏起报错)
体验了一把websocket

上一篇:带心跳的websocket


下一篇:Stream sorted排序案例