websocket receive方法内 有循环怎么退出_WebSocket了解一下
前言
這兩天在調試一個WebSocket的接口,折騰了一天的時間終于弄好了。現在對WebSocket的相關知識點做一個記錄。主要從如下幾個方面進行介紹。
WebSocket的概念
HTTP請求是基于請求響應的模式,永遠是客戶端請求服務器端,是單向的請求。如果服務器端有連續的狀態變化,客戶端就需要通過輪詢的方式去獲知。也就是每隔一段時間,就發出一個詢問,了解服務器有沒有新消息,輪詢的效率比較低,非常浪費資源。WebSocket的最大特點就是服務器可以主動向客戶端推送消息,客戶端也可以主動向服務器端發送消息,是真正的雙向平等通信,也就是全雙工通信。
WebSocket的特點
1.建立在TCP協議之上,服務器的實現比較容易。2.與HTTP協議有著良好的兼容性,默認端口號也是80和443,并且握手階段采用的是HTTP協議,因此握手時不容易屏蔽,能通過各種HTTP代理服務器。3.數據格式比較輕量,性能開銷小,通信高效。4.沒有同源限制,原生支持跨域,客戶端可以與任意服務器通信。5.協議標識符是ws(如果加密,則為wss),服務器網址就是URL。
WebSocket的工作過程
建立一個WebSocket連接,客戶端瀏覽器首先要向服務器發起一個HTTP請求,這個請求和通常的HTTP請求不同,包含了一些附加頭信息。客戶端請求
GET / HTTP/1.1Request URL: ws://localhost:8080/webSocketServer/websocket/testnameConnection: UpgradeHost: localhost:8080Origin: http://localhost:63342Pragma: no-cacheSec-WebSocket-Extensions: permessage-deflate; client_max_window_bitsSec-WebSocket-Key: oxTUjq93ipRDk4gXWhi+mg==Sec-WebSocket-Version: 13Upgrade: websocket服務器響應
Connection: upgradeDate: Sat, 03 Oct 2020 03:26:03 GMTSec-WebSocket-Accept: Jjxh2cOWicbJdcdZ3rhcAeNdoHQ=Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15Upgrade: websocketConnection 必須設置Upgrade,表示客戶端希望連接升級。Upgrade字段必須設置WebSocket,表示希望升級到Websocket協議。Sec-WebSocket-Key 是隨機的字符串,服務器會用這些數據來構造出一個SHA-1的信息摘要,把" Sec-WebScoket-Key"加上一個特殊字符串"oxTUjq93ipRDk4gXWhi+mg=="然后計算 SHA-1 摘要,之后進行 BASE-64編碼,將結果做為 “Sec-WebSocket-Accept” 頭的值,返回給客戶端。如此操作,可以盡量避免普通 HTTP 請求被誤認為Websocket 協議。服務器解析這些附加的頭信息然后產生應答信息返回給客戶端,客戶端和服務器端的WebSocket連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,并且這個連接會持續存在直到客戶端或者服務器端的某一方主動的關閉連接,http和WebSocket的連接生命周期如下:
在SpringBoot中整合WebSocket
服務端
引入依賴
首先我們需要引入WebSocket的starter模塊,這個模塊的作用開啟WebSocket的模塊功能,如下所示:
org.springframework.boot spring-boot-starter-websocket配置基礎類
依賴引入之后,我們需要配置ServerEndpointExporter的Bean,這個Bean作用是我們可以通過@ServerEndpoint注解聲明WebSocket。
@Componentpublic class WebSocketConfig { /** * ServerEndpointExporter作用 * 這個Bean會自動注冊使用@ServerEndpoint注解聲明的websocket endpoint */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}編寫websocket的服務端接口
準備工作做好之后,接下來就是編寫WebSocket的服務端的接口,在此Controller中,定義了Session類,通過它來給客戶端發送消息,通過ConcurrentHashMap來存儲當前連接的客戶端。
@Component@ServerEndpoint("/websocket/{name}")public class WebSocketController { /** * 與某個客戶端的連接對話,需要通過它來給客戶端發送消息 */ private Session session; /** * 標識當前連接客戶端的用戶名 */ private String name; private static ConcurrentHashMap websocketSet = new ConcurrentHashMap<>(); @OnOpen public void OnOpen(Session session, @PathParam(value = "name") String name) { this.session = session; this.name = name; //name是用來表示唯一客戶端,如果需要指定發送,需要指定發送通過name來區分 websocketSet.put(name, this); log.info("[WebSocket]連接成功,當前連接人數為={}", websocketSet.size()); } @OnClose public void OnClose() { websocketSet.remove(this.name); log.info("[WebSocket]退出成功,當前連接人數為={}", websocketSet.size()); } @OnMessage public void OnMessage(String message) { log.info("[WebSocket]收到消息={}", message); groupSending("客戶端的消息我已經收到了"); } public void groupSending(String message) { for (String name : websocketSet.keySet()) { try { websocketSet.get(name).session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } }}我們通過@ServerEndpoint注解標識這個類是一個WebSocket接口,通過@OnOpen標記的方法進行WebSocket的服務連接,通過@OnMessage標記的方法進行消息的接收,以及響應消息給客戶端,其中給客戶端發送消息?websocketSet.get(name).session.getBasicRemote().sendText(message);?getBasicRemote()的方法表示通過同步的方式發送消息,getAsyncRemote()的方法表示通過異步的方式發送消息。通過@OnClose標記的方法進行服務的關閉。
客戶端的調用
客戶端的調用有好幾種方式,我們可以通過JS的方式,實例化WebSocketClient的方式,運用OkHttpClient的方式,下面就分別對這三種方式的調用做一個介紹。
通過JS的方式調用服務
var websocket = null; if ('WebSocket' in window) { //用于創建WebSocket對象,webSocketTest對應的是java類的注解值。 websocket = new WebSocket("ws://localhost:8080/webSocketServer/websocket/testname"); } else { alert("當前瀏覽器不支持"); }// 連接發生錯誤的時候回調方法; websocket.onerror = function () { alert("連接錯誤"); }// 連接成功時建立回調方法 websocket.onopen = function () { //WebSocket已連接上,使用send()方法發送數據 alert("連接成功"); };// 收到消息的回調方法 websocket.onmessage = function (msg) { setdivInnerHTML(msg.data); }; //連接關閉的回調方法 websocket.onclose = function () { closed(); alert("關閉成功"); }; function closed() { websocket.close(); alert("點擊關閉"); } function send() { var message=document.getElementById("message").value; //注意引號內的內容應該是文本框的id而不能是name alert(message); websocket.send(message); //給后臺發送數據 }同樣的首先是實例化一個WebSocket對象,然后通過onmessage回調方法接受服務端響應的結果,通過send方法給后臺發送數據。
通過實例化WebSocketClient的方式
1.引入依賴
org.java-websocket Java-WebSocket 1.3.5同樣的我們需要進行客戶端的配置,也就是實例化一個WebSocketClient的實例。主要是建立連接,發送消息。
@Bean public WebSocketClient webSocketClient() { try { WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://localhost:8080/webSocketServer/websocket/name1"), new Draft_6455()) { @Override public void onOpen(ServerHandshake handshakedata) { log.info("[websocket] 連接成功"); } @Override public void onMessage(String message) { log.info("[websocket] 收到消息={}", message); } @Override public void onClose(int code, String reason, boolean remote) { log.info("[websocket] 退出連接"); } @Override public void onError(Exception ex) { log.info("[websocket] 連接錯誤={}", ex.getMessage()); } }; webSocketClient.connect(); return webSocketClient; } catch (URISyntaxException e) { e.printStackTrace(); } return null; }然后在Controller中通過WebSocketClient的send方法給服務器端發送消息,如下所示;
@RestController@RequestMapping("/websocket")public class WebSocketClientController { @Autowired private WebSocketClient webSocketClient; @RequestMapping("/index") public String sendMessage(String message) { webSocketClient.send("測試消息"); return "消息發送成功"; }}這是一種通過后端接口調用服務的方式,當然我們還有其他的方式,就像下面這種通過OkHttpClient的方式。
通過OkHttpClient的方式
同樣的還是先引入依賴。
com.squareup.okhttp3 okhttp 3.9.1然后定義一個類,繼承WebSocketListener,用于建立連接,發送消息。
public class OkHttpClientService extends WebSocketListener { private String result = null; @Override public void onOpen(WebSocket webSocket, Response response) { super.onOpen(webSocket, response); webSocket.send("需要發送的請求數據"); } @Override public void onMessage(WebSocket webSocket, String text) { super.onMessage(webSocket, text); //其中text是接收到的參數 result = text; } public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() //設置超時時間是5秒 .connectTimeout(5, TimeUnit.MINUTES) .build(); //http的請求對應的就是websocket中的ws;https的請求對應的就是websocket中的wss String url = "ws://localhost:8080/webSocketServer/websocket/name2"; //實例化Request對象 Request request = new Request.Builder().url(url).build(); OkHttpClientService okHttpClientService = new OkHttpClientService(); client.newWebSocket(request, okHttpClientService); //輪詢獲取結果 while (okHttpClientService.result == null) { } System.out.println("接口響應的結果=" + okHttpClientService.result); }}同樣的,還是重寫了onOpen方法和onMessage方法,onOpen方法用來發送消息,onMessage方法用來接收服務器的請求。如果是異步的消息的話,我們就需要輪詢獲取結果。
總結
本文簡單首先介紹了WebSocket的基本概念和相關特點,WebSocket是一個全雙工通信的協議,它支持客戶端向服務端發送消息, 也支持服務端向客戶端發送消息, 一次握手,可以多次發送消息。接著就是介紹了在SpringBoot中如何整合WebSocket的相關功能。實現了一個服務端和客戶端。
源碼地址
https://github.com/XWxiaowei/web_socket_demo.git
參考
https://www.jianshu.com/p/9aa969dd1b4d https://blog.csdn.net/weixin_38111957/article/details/86352677
總結
以上是生活随笔為你收集整理的websocket receive方法内 有循环怎么退出_WebSocket了解一下的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue是什么_什么是VUE?vue有什么
- 下一篇: 电视盒子root_电视盒子 免root