web 開發相關筆記 #04# WebSocket
本文的主要內容:
- HTTP VS. WebSocket
- WebSocket 的客戶端實現(JavaScript)
- WebSocket 的服務端實現(Java & apache WebSocketAPI)
- WebSocket 深入學習
HTTP VS. WebSocket
簡單來講, WebSocket 就是一種允許服務端主動向客戶端 PUSH 數據的技術。
傳統的 HTTP 只能是客戶端先主動向服務器發起請求然後獲得服務器響應。
WebSocket是HTML5開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。 在WebSocket API中,瀏覽器和服務器只需要做一個握手的動作,然後,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。 瀏覽器通過 JavaScript 向服務器發出建立 WebSocket 連接的請求,連接建立以後,客戶端和服務器端就可以通過 TCP 連接直接交換數據。 當你獲取 Web Socket 連接後,你可以通過 send() 方法來向服務器發送數據,並通過 onmessage 事件來接收服務器返回的數據。
上面是網絡上對於 websocket 的一段簡短介紹。
值得一提的是,有不少人認為 websocket (於2011年被IETF定為標準RFC 6455)是一項可以取代 AJAX (約 1998 年前後得到應用)的技術。
簡單的草圖(。。自己畫的不太極不嚴謹,例如說ws最開始有個 HTTP 驗證漏掉了。。但是可以表達大概意思吧):
然後是我收集的一些關於 websocket 的資料:
1、WebSocket - Wikipedia 比較權威、全面
2、An Introduction to WebSockets - Treehouse Blog 生動的個人博客
3、websocket.org - Powered by Kaazing 以 websocket 為主題的網站!(websocket.org - WebSocket technology, demos, articles, and products.)
4、菜鳥教程之 websocket 趕時間的看這個。
總而言之,websocket 非常強大,應用也非常多,例如說可以用來構建基於瀏覽器的網頁遊戲、即時聊天工具之類的。
順便收藏(主題無關 ~ ):
What‘s the difference between getRequestURI and getPathInfo methods in HttpServletRequest?
WebSocket 的客戶端實現(JavaScript)
客戶端代碼完全拷貝自上面列出來的資料二:
index.html
<!DOCTYPE html> <htmllang="en"> <head> <meta charset="utf-8"> <title>WebSockets Demo</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="page-wrapper"> <h1>WebSockets Demo</h1> <div id="status">Connecting...</div> <ul id="messages"></ul> <form id="message-form" action="#" method="post"> <textarea id="message" placeholder="Write your message here..." required></textarea> <button type="submit">Send Message</button> <button type="button" id="close">Close Connection</button> </form> </div> <script src="app.js"></script> </body> </html>
/
style.css
*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } html { font-family: Helvetica, Arial, sans-serif; font-size: 100%; background: #333; } #page-wrapper { width: 650px; background: #FFF; padding: 1em; margin: 1em auto; border-top: 5px solid #69c773; box-shadow: 0 2px 10px rgba(0,0,0,0.8); } h1 { margin-top: 0; } #status { font-size: 0.9rem; margin-bottom: 1rem; } .open { color: green; } .closed { color: red; } ul { list-style: none; margin: 0; padding: 0; font-size: 0.95rem; } ul li { padding: 0.5rem 0.75rem; border-bottom: 1px solid #EEE; } ul li:first-child { border-top: 1px solid #EEE; } ul li span { display: inline-block; width: 90px; font-weight: bold; color: #999; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; } .sent { background-color: #F7F7F7; } .received {} #message-form { margin-top: 1.5rem; } textarea { width: 100%; padding: 0.5rem; font-size: 1rem; border: 1px solid #D9D9D9; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); min-height: 100px; margin-bottom: 1rem; } button { display: inline-block; border-radius: 3px; border: none; font-size: 0.9rem; padding: 0.6rem 1em; color: white; margin: 0 0.25rem; text-align: center; background: #BABABA; border-bottom: 1px solid #999; } button[type="submit"] { background: #86b32d; border-bottom: 1px solid #5d7d1f; } button:hover { opacity: 0.75; cursor: pointer; }View Code
/
app.js
window.onload = function() { // Get references to elements on the page. var form = document.getElementById(‘message-form‘); var messageField = document.getElementById(‘message‘); var messagesList = document.getElementById(‘messages‘); var socketStatus = document.getElementById(‘status‘); var closeBtn = document.getElementById(‘close‘); // The rest of the code in this tutorial will go here... // Create a new WebSocket. var socket = new WebSocket(‘ws://echo.websocket.org‘); // Show a connected message when the WebSocket is opened. socket.onopen = function(event) { socketStatus.innerHTML = ‘Connected to: ‘ + event.currentTarget.url; socketStatus.className = ‘open‘; }; // Handle any errors that occur. socket.onerror = function(error) { console.log(‘WebSocket Error: ‘ + error); }; // Send a message when the form is submitted. form.onsubmit = function(e) { e.preventDefault(); // Retrieve the message from the textarea. var message = messageField.value; // Send the message through the WebSocket. socket.send(message); // Add the message to the messages list. messagesList.innerHTML += ‘<li class="sent"><span>Sent:</span>‘ + message + ‘</li>‘; // Clear out the message field. messageField.value = ‘‘; return false; }; // Handle messages sent by the server. socket.onmessage = function(event) { var message = event.data; messagesList.innerHTML += ‘<li class="received"><span>Received:</span>‘ + message + ‘</li>‘; }; // Show a disconnected message when the WebSocket is closed. socket.onclose = function(event) { socketStatus.innerHTML = ‘Disconnected from WebSocket.‘; socketStatus.className = ‘closed‘; }; // Close the WebSocket connection when the close button is clicked. closeBtn.onclick = function(e) { e.preventDefault(); // Close the WebSocket. socket.close(); return false; }; };
/
直接把 三個文件放在同一個目錄下,用瀏覽器打開 index.html 就可以用了。連接的是代碼原作者的 websocket 服務器哦!
WebSocket 的服務端實現(Java & apache WebSocketAPI)
構建WebSocket 服務器的方式有很多,不過我只會用 tomcat 的 API,代碼即是 Tomcat 的 websocket example 相比自己寫的肯定比較規範啦。↓
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sample.web; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; 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") public class ChatAnnotation { private static final String GUEST_PREFIX = "Guest"; private static final AtomicInteger connectionIds = new AtomicInteger(0); private static final Set<ChatAnnotation> connections = new CopyOnWriteArraySet<>(); private final String nickname; private Session session; public ChatAnnotation() { 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 { } private static void broadcast(String msg) { for (ChatAnnotation 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); } } } }
在運行之前需要修改 app.js 中的地址:
// The rest of the code in this tutorial will go here... // Create a new WebSocket. var socket = new WebSocket(‘ws://localhost:8080/websocket‘);
WebSocket 深入學習
當然,上面僅用到了 WebSocket API 的一個小子集,要想真正用好這些 API 並沒那麽簡單。下面是我找到的一些學習資料(基本上看 URL 就知道什麽內容了):
1、https://docs.oracle.com/javaee/7/api/javax/websocket/package-summary.html
2、https://docs.oracle.com/javaee/7/tutorial/websocket.htm
3、http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html
4、https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java
5、http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/HomeWebsocket/WebsocketHome.html
6、http://www.baeldung.com/java-websockets
7、https://tomcat.apache.org/tomcat-9.0-doc/websocketapi/index.html
8、https://benas.github.io/2016/02/21/using-the-java-api-for-webSocket-to-create-a-chat-server.html
web 開發相關筆記 #04# WebSocket