初識websocket

一、定義


websocket.jpg

WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信——允許服務(wù)器主動發(fā)送信息給客戶端。
WebSocket協(xié)議支持(在受控環(huán)境中運(yùn)行不受信任的代碼的)客戶端與(選擇加入該代碼的通信的)遠(yuǎn)程主機(jī)之間進(jìn)行全雙工通信。
二、產(chǎn)生的背景
簡單的說,WebSocket協(xié)議之前,雙工通信是通過不停發(fā)送HTTP請求,從服務(wù)器拉取更新來實(shí)現(xiàn),這導(dǎo)致了效率低下。WebSocket解決了這個問題
三、解決的問題
1.服務(wù)器被迫為每個客戶端使用許多不同的底層TCP連接:一個用于向客戶端發(fā)送信息,其它用于接收每個傳入消息。
2.有些協(xié)議有很高的開銷,每一個客戶端和服務(wù)器之間都有HTTP頭。
3.客戶端腳本被迫維護(hù)從傳出連接到傳入連接的映射來追蹤回復(fù)。
四、實(shí)現(xiàn)原理和好處
1、原理:在實(shí)現(xiàn)websocket連線過程中,需要通過瀏覽器發(fā)出websocket連線請求,然后服務(wù)器發(fā)出回應(yīng),這個過程通常稱為“握手” 。
2、好處
① Header
互相溝通的Header是很小的-大概只有 2 Bytes
②Server Push
服務(wù)器的推送,服務(wù)器不再被動的接收到瀏覽器的請求之后才返回?cái)?shù)據(jù),而是在有新數(shù)據(jù)時就主動推送給瀏覽器。

五、請求響應(yīng)案例
瀏覽器請求
GET /webfin/websocket/ HTTP/1.1

Host: localhost
  Upgrade: websocket

Connection: Upgrade
  Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
  Origin: http://服務(wù)器地址
  Sec-WebSocket-Version: 13

服務(wù)器回應(yīng)
HTTP/1.1 101 Switching Protocols
  Upgrade: websocket
  Connection: Upgrade
  Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
WebSocket借用http請求進(jìn)行握手,相比正常的http請求,多了一些內(nèi)容。
其中,Upgrade: websocket
Connection: Upgrade
表示希望將http協(xié)議升級到Websocket協(xié)議。
Sec-WebSocket-Key是瀏覽器隨機(jī)生成的base64 encode的值,用來詢問服務(wù)器是否是支持WebSocket。

服務(wù)器返回
Upgrade: websocket
Connection: Upgrade
告訴瀏覽器即將升級的是Websocket協(xié)議
Sec-WebSocket-Accept是將請求包“Sec-WebSocket-Key”的值,與”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″這個字符串進(jìn)行拼接,然后對拼接后的字符串進(jìn)行sha-1運(yùn)算,再進(jìn)行base64編碼得到的。用來說明自己是WebSocket助理服務(wù)器。

六、個人demo
1.服務(wù)端
/*

  • websocket服務(wù)端

  • 客戶端向服務(wù)器端建立websocket的url

  • */
    @ServerEndpoint("/websocket")
    @Component
    public class WebSocketServer {
    //計(jì)算當(dāng)前在線人數(shù)
    private static int onlineCount=0;
    //concurrent包的線程安全set,用來存放每個客戶端對應(yīng)的mywebsocket對象,必須
    private static CopyOnWriteArraySet<WebSocketServer>webSocketSet=new CopyOnWriteArraySet<>();
    //與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù),必須
    private Session session;

    /*

    • 連接建立成功使用的方法
    • /
      @OnOpen
      public void onOpen(Session session){
      this.session=session;
      webSocketSet.add(this);
      addOnlineCount(); //在線數(shù)加1
      System.out.println("有新窗口開始監(jiān)聽,當(dāng)前在線人數(shù)為" + getOnlineCount());
      try {
      sendMessage("連接成功");
      } catch (IOException e) {
      System.out.println("WebSocket IO異常");
      }
      }
      /

      連接關(guān)閉調(diào)用的方法
      /
      @OnClose
      public void onClose() {
      webSocketSet.remove(this); //從set中刪除
      subOnlineCount(); //在線數(shù)減1
      System.out.println("有連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount());
      }
      /
    • 收到客戶端消息后調(diào)用的方法
    • @param message 客戶端發(fā)送過來的消息
      /
      @OnMessage
      public void onMessage(String message, Session session) {
      System.out.println("收到客戶端的信息:" + message);
      //群發(fā)消息
      for (WebSocketServer item : webSocketSet) {
      try {
      item.sendMessage(message);
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      /
      *
    • @param session
    • @param error
      */
      @OnError
      public void onError(Session session, Throwable error) {
      System.out.println("發(fā)生錯誤");
      error.printStackTrace();
      }

    /**

    • 實(shí)現(xiàn)服務(wù)器主動推送
      */
      public void sendMessage(String message) throws IOException {
      this.session.getBasicRemote().sendText(message);
      }
/**
 * 群發(fā)自定義消息
 */
public static void sendInfo(String message) throws IOException {
    System.out.println("推送消息內(nèi)容:" + message);
    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--;
}

}
2.配置webSocket
/*

  • WEBSOCKET配置類

  • 開啟websocket支持

  • */
    @Configuration
    public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
    return new ServerEndpointExporter();
    }
    }
    3.提供接口
    @RestController
    @RequestMapping(value = "/socket")
    public class WebSocketController {
    //推送數(shù)據(jù)接口
    @RequestMapping("/push")
    public String pushMsg(HttpServletRequest request) {
    String message=request.getParameter("info");
    try {
    WebSocketServer.sendInfo(message);
    } catch (IOException e) {
    e.printStackTrace();
    }
    return "success";
    }
    }
    4.主類
    @SpringBootApplication
    public class WebsocketApplication {

    public static void main(String[] args) {
    SpringApplication.run(WebsocketApplication.class, args);
    }
    }
    5.前端客戶端
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>websocket頁面</title>
    <style>
    .ta1{
    width: 400px;
    height: 400px;
    overflow-x:hidden;
    background-color: tan
    }
    .ta2{
    width:400px;
    height:200px;
    overflow-x:hidden;
    background-color: aquamarine;
    }
    .one{
    width: 300px;
    height: 30px;
    border-radius: 5px;
    background-color: lightcoral
    }
    .two{
    width: 50px;
    height: 30px;
    background-color: cadetblue;
    border-radius: 5px;
    }
    body{
    text-align: center;
    }
    </style>
    </head>
    <body>
    <h2>WebSocket練習(xí)</h2>



    <script>
    function sendone() {
    socket.send(document.getElementById("userMsg").value);
    document.getElementById("userMsg").value=null;
    }
    var socket;
    if (typeof(WebSocket) == "undefined") {
    console.log("您的瀏覽器不支持WebSocket");
    } else {
    console.log("您的瀏覽器支持WebSocket");
    //實(shí)現(xiàn)化WebSocket對象,指定要連接的服務(wù)器地址與端口建立連接
    socket = new WebSocket("ws://localhost:8080/websocket");

      //打開事件
      socket.onopen = function () {
          console.log("Socket已打開");
          //socket.send("這是來自客戶端的消息:" + new Date());
      };
    
      //獲得消息事件
      socket.onmessage = function (msg) {
          console.log(msg.data);
          alert(msg.data);
          document.getElementById("tao").value=document.getElementById("tao").value+'\n'+msg.data;
      };
    
      //關(guān)閉事件
      socket.onclose = function () {
          console.log("Socket已關(guān)閉");
      };
    
      //發(fā)生了錯誤事件
      socket.onerror = function () {
          alert("Socket發(fā)生了錯誤");
      }
    

    }
    </script>
    <h3>消息顯示區(qū)域</h3>
    <div>
    <textarea class="ta1" id="tao">

    </textarea>
    </div>
    <div>
    <input type="text" class="one" placeholder="輸入你要發(fā)送的信息" value="" id="userMsg">
    <input type="button" class="two" value="發(fā)送" onclick="sendone()">
    </div>



    <h3>服務(wù)器端廣播消息區(qū)域</h3>
    <div>
    <textarea class="ta2">

    </textarea>
    </div>
    </body>
    </html>
    6.前端服務(wù)器端
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>server頁面</title>
    <style>
    textarea{
    width:200px;
    height: 30px;
    background-color: lightcoral;
    overflow-x:hidden;
    }
    .two{
    width: 50px;
    height: 30px;
    background-color: cadetblue;
    border-radius: 5px;
    }
    body{
    text-align: center;
    }
    </style>
    </head>
    <body>
    <h3>服務(wù)器推送消息</h3>

<form action="/socket/push" method="post" accept-charset="utf-8" name="loginfrom">
<textarea id="info" name="info"></textarea>
<input type="submit" class="two" value="發(fā)送">
</form>

</body

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,942評論 1 92
  • 什么是WebSocket WebSocket 是一種在單個TCP連接上進(jìn)行全雙工通訊的協(xié)議,屬于應(yīng)用層協(xié)議。它基于...
    九又四分之三o閱讀 517評論 0 2
  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢夢敢當(dāng)閱讀 9,032評論 0 50
  • 在項(xiàng)目中用到socket.io在WEB端做消息推送,遂花了點(diǎn)時間看了socket.io實(shí)現(xiàn),做個簡單分析,如有錯漏...
    __七把刀__閱讀 30,228評論 20 54
  • 巴渝墨客 2018-8-11 凌晨時分 ※題記: 在物質(zhì)至上的今天,這是時代造就的產(chǎn)物——讓我們所有人都趨...
    巴渝墨客閱讀 739評論 0 1

友情鏈接更多精彩內(nèi)容