日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

websocket receive方法内 有循环怎么退出_WebSocket了解一下

發(fā)布時(shí)間:2025/3/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 websocket receive方法内 有循环怎么退出_WebSocket了解一下 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

這兩天在調(diào)試一個(gè)WebSocket的接口,折騰了一天的時(shí)間終于弄好了。現(xiàn)在對(duì)WebSocket的相關(guān)知識(shí)點(diǎn)做一個(gè)記錄。主要從如下幾個(gè)方面進(jìn)行介紹。

WebSocket的概念

HTTP請(qǐng)求是基于請(qǐng)求響應(yīng)的模式,永遠(yuǎn)是客戶端請(qǐng)求服務(wù)器端,是單向的請(qǐng)求。如果服務(wù)器端有連續(xù)的狀態(tài)變化,客戶端就需要通過(guò)輪詢的方式去獲知。也就是每隔一段時(shí)間,就發(fā)出一個(gè)詢問(wèn),了解服務(wù)器有沒(méi)有新消息,輪詢的效率比較低,非常浪費(fèi)資源。WebSocket的最大特點(diǎn)就是服務(wù)器可以主動(dòng)向客戶端推送消息,客戶端也可以主動(dòng)向服務(wù)器端發(fā)送消息,是真正的雙向平等通信,也就是全雙工通信。

WebSocket的特點(diǎn)

1.建立在TCP協(xié)議之上,服務(wù)器的實(shí)現(xiàn)比較容易。2.與HTTP協(xié)議有著良好的兼容性,默認(rèn)端口號(hào)也是80和443,并且握手階段采用的是HTTP協(xié)議,因此握手時(shí)不容易屏蔽,能通過(guò)各種HTTP代理服務(wù)器。3.數(shù)據(jù)格式比較輕量,性能開(kāi)銷(xiāo)小,通信高效。4.沒(méi)有同源限制,原生支持跨域,客戶端可以與任意服務(wù)器通信。5.協(xié)議標(biāo)識(shí)符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是URL。

WebSocket的工作過(guò)程

建立一個(gè)WebSocket連接,客戶端瀏覽器首先要向服務(wù)器發(fā)起一個(gè)HTTP請(qǐng)求,這個(gè)請(qǐng)求和通常的HTTP請(qǐng)求不同,包含了一些附加頭信息。客戶端請(qǐng)求

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

服務(wù)器響應(yīng)

Connection: upgradeDate: Sat, 03 Oct 2020 03:26:03 GMTSec-WebSocket-Accept: Jjxh2cOWicbJdcdZ3rhcAeNdoHQ=Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15Upgrade: websocket

Connection 必須設(shè)置Upgrade,表示客戶端希望連接升級(jí)。Upgrade字段必須設(shè)置WebSocket,表示希望升級(jí)到Websocket協(xié)議。Sec-WebSocket-Key 是隨機(jī)的字符串,服務(wù)器會(huì)用這些數(shù)據(jù)來(lái)構(gòu)造出一個(gè)SHA-1的信息摘要,把" Sec-WebScoket-Key"加上一個(gè)特殊字符串"oxTUjq93ipRDk4gXWhi+mg=="然后計(jì)算 SHA-1 摘要,之后進(jìn)行 BASE-64編碼,將結(jié)果做為 “Sec-WebSocket-Accept” 頭的值,返回給客戶端。如此操作,可以盡量避免普通 HTTP 請(qǐng)求被誤認(rèn)為Websocket 協(xié)議。服務(wù)器解析這些附加的頭信息然后產(chǎn)生應(yīng)答信息返回給客戶端,客戶端和服務(wù)器端的WebSocket連接就建立起來(lái)了,雙方就可以通過(guò)這個(gè)連接通道自由的傳遞信息,并且這個(gè)連接會(huì)持續(xù)存在直到客戶端或者服務(wù)器端的某一方主動(dòng)的關(guān)閉連接,http和WebSocket的連接生命周期如下:

在SpringBoot中整合WebSocket

服務(wù)端

引入依賴

首先我們需要引入WebSocket的starter模塊,這個(gè)模塊的作用開(kāi)啟WebSocket的模塊功能,如下所示:

org.springframework.boot spring-boot-starter-websocket

配置基礎(chǔ)類(lèi)

依賴引入之后,我們需要配置ServerEndpointExporter的Bean,這個(gè)Bean作用是我們可以通過(guò)@ServerEndpoint注解聲明WebSocket。

@Componentpublic class WebSocketConfig { /** * ServerEndpointExporter作用 * 這個(gè)Bean會(huì)自動(dòng)注冊(cè)使用@ServerEndpoint注解聲明的websocket endpoint */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}

編寫(xiě)websocket的服務(wù)端接口

準(zhǔn)備工作做好之后,接下來(lái)就是編寫(xiě)WebSocket的服務(wù)端的接口,在此Controller中,定義了Session類(lèi),通過(guò)它來(lái)給客戶端發(fā)送消息,通過(guò)ConcurrentHashMap來(lái)存儲(chǔ)當(dāng)前連接的客戶端。

@Component@ServerEndpoint("/websocket/{name}")public class WebSocketController { /** * 與某個(gè)客戶端的連接對(duì)話,需要通過(guò)它來(lái)給客戶端發(fā)送消息 */ private Session session; /** * 標(biāo)識(shí)當(dāng)前連接客戶端的用戶名 */ 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是用來(lái)表示唯一客戶端,如果需要指定發(fā)送,需要指定發(fā)送通過(guò)name來(lái)區(qū)分 websocketSet.put(name, this); log.info("[WebSocket]連接成功,當(dāng)前連接人數(shù)為={}", websocketSet.size()); } @OnClose public void OnClose() { websocketSet.remove(this.name); log.info("[WebSocket]退出成功,當(dāng)前連接人數(shù)為={}", websocketSet.size()); } @OnMessage public void OnMessage(String message) { log.info("[WebSocket]收到消息={}", message); groupSending("客戶端的消息我已經(jīng)收到了"); } public void groupSending(String message) { for (String name : websocketSet.keySet()) { try { websocketSet.get(name).session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } }}

我們通過(guò)@ServerEndpoint注解標(biāo)識(shí)這個(gè)類(lèi)是一個(gè)WebSocket接口,通過(guò)@OnOpen標(biāo)記的方法進(jìn)行WebSocket的服務(wù)連接,通過(guò)@OnMessage標(biāo)記的方法進(jìn)行消息的接收,以及響應(yīng)消息給客戶端,其中給客戶端發(fā)送消息?websocketSet.get(name).session.getBasicRemote().sendText(message);?getBasicRemote()的方法表示通過(guò)同步的方式發(fā)送消息,getAsyncRemote()的方法表示通過(guò)異步的方式發(fā)送消息。通過(guò)@OnClose標(biāo)記的方法進(jìn)行服務(wù)的關(guān)閉。

客戶端的調(diào)用

客戶端的調(diào)用有好幾種方式,我們可以通過(guò)JS的方式,實(shí)例化WebSocketClient的方式,運(yùn)用OkHttpClient的方式,下面就分別對(duì)這三種方式的調(diào)用做一個(gè)介紹。

通過(guò)JS的方式調(diào)用服務(wù)

var websocket = null; if ('WebSocket' in window) { //用于創(chuàng)建WebSocket對(duì)象,webSocketTest對(duì)應(yīng)的是java類(lèi)的注解值。 websocket = new WebSocket("ws://localhost:8080/webSocketServer/websocket/testname"); } else { alert("當(dāng)前瀏覽器不支持"); }// 連接發(fā)生錯(cuò)誤的時(shí)候回調(diào)方法; websocket.onerror = function () { alert("連接錯(cuò)誤"); }// 連接成功時(shí)建立回調(diào)方法 websocket.onopen = function () { //WebSocket已連接上,使用send()方法發(fā)送數(shù)據(jù) alert("連接成功"); };// 收到消息的回調(diào)方法 websocket.onmessage = function (msg) { setdivInnerHTML(msg.data); }; //連接關(guān)閉的回調(diào)方法 websocket.onclose = function () { closed(); alert("關(guān)閉成功"); }; function closed() { websocket.close(); alert("點(diǎn)擊關(guān)閉"); } function send() { var message=document.getElementById("message").value; //注意引號(hào)內(nèi)的內(nèi)容應(yīng)該是文本框的id而不能是name alert(message); websocket.send(message); //給后臺(tái)發(fā)送數(shù)據(jù) }

同樣的首先是實(shí)例化一個(gè)WebSocket對(duì)象,然后通過(guò)onmessage回調(diào)方法接受服務(wù)端響應(yīng)的結(jié)果,通過(guò)send方法給后臺(tái)發(fā)送數(shù)據(jù)。

通過(guò)實(shí)例化WebSocketClient的方式

1.引入依賴

org.java-websocket Java-WebSocket 1.3.5

同樣的我們需要進(jìn)行客戶端的配置,也就是實(shí)例化一個(gè)WebSocketClient的實(shí)例。主要是建立連接,發(fā)送消息。

@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] 連接錯(cuò)誤={}", ex.getMessage()); } }; webSocketClient.connect(); return webSocketClient; } catch (URISyntaxException e) { e.printStackTrace(); } return null; }

然后在Controller中通過(guò)WebSocketClient的send方法給服務(wù)器端發(fā)送消息,如下所示;

@RestController@RequestMapping("/websocket")public class WebSocketClientController { @Autowired private WebSocketClient webSocketClient; @RequestMapping("/index") public String sendMessage(String message) { webSocketClient.send("測(cè)試消息"); return "消息發(fā)送成功"; }}

這是一種通過(guò)后端接口調(diào)用服務(wù)的方式,當(dāng)然我們還有其他的方式,就像下面這種通過(guò)OkHttpClient的方式。

通過(guò)OkHttpClient的方式

同樣的還是先引入依賴。

com.squareup.okhttp3 okhttp 3.9.1

然后定義一個(gè)類(lèi),繼承WebSocketListener,用于建立連接,發(fā)送消息。

public class OkHttpClientService extends WebSocketListener { private String result = null; @Override public void onOpen(WebSocket webSocket, Response response) { super.onOpen(webSocket, response); webSocket.send("需要發(fā)送的請(qǐng)求數(shù)據(jù)"); } @Override public void onMessage(WebSocket webSocket, String text) { super.onMessage(webSocket, text); //其中text是接收到的參數(shù) result = text; } public static void main(String[] args) { OkHttpClient client = new OkHttpClient.Builder() //設(shè)置超時(shí)時(shí)間是5秒 .connectTimeout(5, TimeUnit.MINUTES) .build(); //http的請(qǐng)求對(duì)應(yīng)的就是websocket中的ws;https的請(qǐng)求對(duì)應(yīng)的就是websocket中的wss String url = "ws://localhost:8080/webSocketServer/websocket/name2"; //實(shí)例化Request對(duì)象 Request request = new Request.Builder().url(url).build(); OkHttpClientService okHttpClientService = new OkHttpClientService(); client.newWebSocket(request, okHttpClientService); //輪詢獲取結(jié)果 while (okHttpClientService.result == null) { } System.out.println("接口響應(yīng)的結(jié)果=" + okHttpClientService.result); }}

同樣的,還是重寫(xiě)了onOpen方法和onMessage方法,onOpen方法用來(lái)發(fā)送消息,onMessage方法用來(lái)接收服務(wù)器的請(qǐng)求。如果是異步的消息的話,我們就需要輪詢獲取結(jié)果。

總結(jié)

本文簡(jiǎn)單首先介紹了WebSocket的基本概念和相關(guān)特點(diǎn),WebSocket是一個(gè)全雙工通信的協(xié)議,它支持客戶端向服務(wù)端發(fā)送消息, 也支持服務(wù)端向客戶端發(fā)送消息, 一次握手,可以多次發(fā)送消息。接著就是介紹了在SpringBoot中如何整合WebSocket的相關(guān)功能。實(shí)現(xiàn)了一個(gè)服務(wù)端和客戶端。

源碼地址

https://github.com/XWxiaowei/web_socket_demo.git

參考

https://www.jianshu.com/p/9aa969dd1b4d https://blog.csdn.net/weixin_38111957/article/details/86352677

總結(jié)

以上是生活随笔為你收集整理的websocket receive方法内 有循环怎么退出_WebSocket了解一下的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。