文章出處

WebSocket是什么呢?

  WebSocket一種在單個 TCP 連接上進行全雙工通訊的協議。WebSocket通信協議于2011年被IETF定為標準RFC 6455,并被RFC7936所補充規范,WebSocketAPI被W3C定為標準。

WebSocket 是獨立的、創建在 TCP 上的協議,和 HTTP 的唯一關聯是使用 HTTP 協議的101狀態碼進行協議切換,使用的 TCP 端口是80,可以用于繞過大多數防火墻的限制。

WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端直接向客戶端推送數據而不需要客戶端進行請求,在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,并允許數據進行雙向傳送。

目前常見的瀏覽器如 Chrome、IE、Firefox、Safari、Opera 等都支持 WebSocket,同時需要服務端程序支持 WebSocket。

    --------------------------------------------------------------------------------------

以上摘自wiki,總的來說websocket實現了服務器和瀏覽器之間的雙向通信,擺脫了以往的一問一答的通信方式,可以自由地傳輸數據.

Websocket有什么優點?

  • 由于沒有http頭信息,所以傳輸的數據包很小
  • 服務器可以主動推送信息

Websocket的握手協議

還是照搬wiki上的例子,websocket在建立連接時,瀏覽器會向服務器發出如下請求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: null
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

這段請求會告訴服務器即將切換到websocket協議,如果服務器支持的話,會返回如下信息

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Origin: null
Sec-WebSocket-Location: ws://example.com/

至此,握手階段完成,服務器和瀏覽器之間可以開始發送和接收信息

使用Websocket實現一個簡單的網頁聊天室

  • 使用tomcat8的websocket-api
  • 參考tomcat自帶的example

服務器端ChatServlet

package com.yc.chatroom;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.annotation.WebServlet;
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;
@ServerEndpoint(value="/websocket/chat")//指定客戶端連接地址
public class ChatServlet {
  private static final long serialVersionUID = 1L;
  private static final String GUEST_PREFIX = "Guest";
  private static final AtomicInteger connectionIds = new AtomicInteger(0);
  private static final Set<ChatServlet> connections = new CopyOnWriteArraySet<ChatServlet>();
  private final String nickname;
  private Session session;
  public ChatServlet() {
    nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
  }
  @OnOpen
  public void start(Session session) {
    this.session = session;
    connections.add(this);
    String message = String.format("* %s %s", nickname, "has joined.");
    broadcast(message); //廣播用戶加入消息
  }
  @OnClose
  public void end() {
    connections.remove(this);
    String message = String.format("* %s %s", nickname, "has disconnected.");
    broadcast(message); //廣播用戶推出消息
  }
  @OnMessage
  public void incoming(String message) {
    // Never trust the client
    String filteredMessage = String.format("%s: %s", nickname, message.toString());
    broadcast(filteredMessage); //廣播發送內容
  }
  @OnError
  public void onError(Throwable t) throws Throwable {
    t.printStackTrace();
  }
  private static void broadcast(String msg) {
    for (ChatServlet client : connections) {
      try {
        synchronized (client) {
          client.session.getBasicRemote().sendText(msg);//給每個人發送消息
        }
      } catch (IOException e) {
        connections.remove(client);
        try {
          client.session.close();
        } catch (IOException e1) {
          // Ignore
        }
        String message = String.format("* %s %s", client.nickname, "has been disconnected.");
        broadcast(message);
      }
    }
  }
}

瀏覽器端index.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<title>Apache Tomcat WebSocket Examples: Chat</title>
<style type="text/css">
input#chat {
  width: 410px
}
#console-container {
  width: 400px;
}
#console {
  border: 1px solid #CCCCCC;
  border-right-color: #999999;
  border-bottom-color: #999999;
  height: 170px;
  overflow-y: scroll;
  padding: 5px;
  width: 100%;
}
#console p {
  padding: 0;
  margin: 0;
}
</style>
</head>
<body>
  <div>
    <p>
      <input type="text" placeholder="type and press enter to chat"
        id="chat" />
    </p>
    <div id="console-container">
      <div id="console"></div>
    </div>
  </div>
</body>
<script type="text/javascript">
  /**
  *  指定要連接的websocket地址
  *  如果使用https,則使用wss://
  **/
  var socket = new WebSocket('ws://' + window.location.host+ '/chatroom/websocket/chat');
  
  //連接與服務器的連接
  socket.onopen = function() {
    showMsg('Info: WebSocket connection opened.');
    document.getElementById('chat').onkeydown = function(event) {
      if (event.keyCode == 13) {
        sendMsg();
      }
    };
  };
  //斷開與服務器的連接
  socket.onclose = function() {
    document.getElementById('chat').onkeydown = null;
    showMsg('Info: WebSocket closed.');
  };
  //與服務器之間的通信
  socket.onmessage = function(message) {
    showMsg(message.data);
  };
  //顯示消息
  function showMsg(message) {
    var console = document.getElementById('console');
    var p = document.createElement('p');
    p.style.wordWrap = 'break-word';
    p.innerHTML = message;
    console.appendChild(p);
    while (console.childNodes.length > 25) {
      console.removeChild(console.firstChild);
    }
    console.scrollTop = console.scrollHeight;
  }
  //發送消息
  function sendMsg() {
    var message = document.getElementById('chat').value;
    if (message != '') {
      socket.send(message);
      document.getElementById('chat').value = '';
    }
  }
</script>

運行結果

一次打開兩個窗口,用戶依次為guest0, guest1

guest0:

guest1:

guest0退出:

 

原文鏈接地址:https://mssora.com/websocket-intro-and-chatroom/

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()