國外網(wǎng)站代理如何查詢網(wǎng)站收錄情況
一、WebSocket簡介
HTML5規(guī)范在傳統(tǒng)的web交互基礎(chǔ)上為我們帶來了眾多的新特性,隨著web技術(shù)被廣泛用于web APP的開發(fā),這些新特性得以推廣和使用,而websocket作為一種新的web通信技術(shù)具有巨大意義。WebSocket是HTML5新增的協(xié)議,它的目的是在瀏覽器和服務(wù)器之間建立一個(gè)不受限的雙向通信的通道,比如說,服務(wù)器可以在任意時(shí)刻發(fā)送消息給瀏覽器。支持雙向通信。
二、WebSocket通信原理及機(jī)制
websocket是基于瀏覽器端的web技術(shù),那么它的通信肯定少不了http,websocket本身雖然也是一種新的應(yīng)用層協(xié)議,但是它也不能夠脫離http而單獨(dú)存在。具體來講,我們在客戶端構(gòu)建一個(gè)websocket實(shí)例,并且為它綁定一個(gè)需要連接到的服務(wù)器地址,當(dāng)客戶端連接服務(wù)端的時(shí)候,會(huì)向服務(wù)端發(fā)送一個(gè)消息報(bào)文
三、WebSocket特點(diǎn)和優(yōu)點(diǎn)
1、支持雙向通信,實(shí)時(shí)性更強(qiáng)。
2、更好的二進(jìn)制支持。
3、較少的控制開銷。連接創(chuàng)建后,ws客戶端、服務(wù)端進(jìn)行數(shù)據(jù)交換時(shí),協(xié)議控制的數(shù)據(jù)包頭部較小。在不包含頭部的情況下,服務(wù)端到客戶端的包頭只有2~10字節(jié)(取決于數(shù)據(jù)包長度),客戶端到服務(wù)端的的話,需要加上額外的4字節(jié)的掩碼。而HTTP協(xié)議每次通信都需要攜帶完整的頭部。
4、支持?jǐn)U展。ws協(xié)議定義了擴(kuò)展,用戶可以擴(kuò)展協(xié)議,或者實(shí)現(xiàn)自定義的子協(xié)議。(比如支持自定義壓縮算法等)
5、建立在tcp協(xié)議之上,服務(wù)端實(shí)現(xiàn)比較容易
6、數(shù)據(jù)格式比較輕量,性能開銷小,通信效率高
7、和http協(xié)議有著良好的兼容性,默認(rèn)端口是80和443,并且握手階段采用HTTP協(xié)議,因此握手的時(shí)候不容易屏蔽,能通過各種的HTTP代理
四、WebSocket心跳機(jī)制
在使用websocket過程中,可能會(huì)出現(xiàn)網(wǎng)絡(luò)斷開的情況,比如信號(hào)不好,或者網(wǎng)絡(luò)臨時(shí)性關(guān)閉,這時(shí)候websocket的連接已經(jīng)斷開,而瀏覽器不會(huì)執(zhí)行websocket 的 onclose方法,我們無法知道是否斷開連接,也就無法進(jìn)行重連操作。如果當(dāng)前發(fā)送websocket數(shù)據(jù)到后端,一旦請求超時(shí),onclose便會(huì)執(zhí)行,這時(shí)候便可進(jìn)行綁定好的重連操作。
? ? ? ?心跳機(jī)制是每隔一段時(shí)間會(huì)向服務(wù)器發(fā)送一個(gè)數(shù)據(jù)包,告訴服務(wù)器自己還活著,同時(shí)客戶端會(huì)確認(rèn)服務(wù)器端是否還活著,如果還活著的話,就會(huì)回傳一個(gè)數(shù)據(jù)包給客戶端來確定服務(wù)器端也還活著,否則的話,有可能是網(wǎng)絡(luò)斷開連接了。需要重連~
?
五、在后端Spring Boot 和前端VUE中如何建立通信
1、在Spring Boot 中 pom.xml中添加 websocket依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、創(chuàng)建 WebSocketConfig.java 開啟websocket支持
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 開啟WebSocket支持* */
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
3、創(chuàng)建?WebSocketServer.java 鏈接
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;@ServerEndpoint("/websocket/testsocket")
@Component
public class WebSocketServer {private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);//靜態(tài)變量,用來記錄當(dāng)前在線連接數(shù)。應(yīng)該把它設(shè)計(jì)成線程安全的。private static int onlineCount = 0;//concurrent包的線程安全Set,用來存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象。private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();//與某個(gè)客戶端的連接會(huì)話,需要通過它來給客戶端發(fā)送數(shù)據(jù)private Session session;/*** 連接建立成功調(diào)用的方法*/@OnOpenpublic void onOpen(Session session) {this.session = session;webSocketSet.add(this); //加入set中addOnlineCount(); //在線數(shù)加1log.info("有新窗口開始監(jiān)聽,當(dāng)前在線人數(shù)為" + getOnlineCount());try {sendMessage("連接成功");} catch (Exception e) {log.error("websocket IO異常");}}/*** 連接關(guān)閉調(diào)用的方法*/@OnClosepublic void onClose(Session session) {try {webSocketSet.remove(this); //從set中刪除subOnlineCount(); //在線數(shù)減1session.close();log.info("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount());} catch (IOException e) {e.printStackTrace();}}/*** 收到客戶端消息后調(diào)用的方法** @param message 客戶端發(fā)送過來的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到的信息:"+message);Map<String, Object> maps = new HashMap<>();maps.put("type", message);this.sendInfo(maps);}/**** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("發(fā)生錯(cuò)誤");error.printStackTrace();}/*** 實(shí)現(xiàn)服務(wù)器主動(dòng)推送*/public void sendMessage(Object obj) {try {synchronized (this.session) {this.session.getBasicRemote().sendText((JSON.toJSONString(obj)));}} catch (Exception e) {e.printStackTrace();}}/*** 群發(fā)自定義消息* */public static void sendInfo(Object obj) {for (WebSocketServer item : webSocketSet) {try {item.sendMessage(obj);} catch (Exception e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}
}
4、創(chuàng)建一個(gè)測試調(diào)用websocket發(fā)送消息?TimerSocketMessage.java (用定時(shí)器發(fā)送推送消息
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;@Component
@EnableScheduling
public class TimerSocketMessage {/*** 推送消息到前臺(tái)*/@Scheduled(cron = "*/5 * * * * * ")public void SocketMessage(){SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Map<String, Object> maps = new HashMap<>();maps.put("type", "sendMessage");maps.put("data", sdf.format(new Date()));WebSocketServer.sendInfo(maps);}
}
5、在VUE中創(chuàng)建和后端 websocket服務(wù)的連接并建立心跳機(jī)制。
<template><div><el-row :gutter="$ui.layout.gutter.g10"><el-col :span="$ui.layout.span.one" style="background-color: #FFFFFF; padding: 10px;"><el-form ref="form" :model="form" label-width="80px" size="small" :inline="true"><el-form-item label="生成數(shù)量"><el-input-number v-model="form.number" :min="1" :max="999" label="描述文字" /></el-form-item><el-form-item label="數(shù)值范圍"><el-input-number v-model="form.start" :min="1" :max="9999999999" label="描述文字" /> ~<el-input-number v-model="form.end" :min="1" :max="9999999999" label="描述文字" /></el-form-item><el-form-item><el-button size="mini" type="primary" @click="spawn">生成</el-button></el-form-item></el-form></el-col></el-row><h1> websocket 消息推送測試:{{data}}</h1></div>
</template><script>
export default {name: 'Index',data() {return {form: {number: 1,start: 1,end: 100},data:0,timeout: 28 * 1000,//30秒一次心跳timeoutObj: null,//心跳心跳倒計(jì)時(shí)serverTimeoutObj: null,//心跳倒計(jì)時(shí)timeoutnum: null,//斷開 重連倒計(jì)時(shí)websocket: null,}},created () {// 初始化websocketthis.initWebSocket()},methods: {spawn() {},initWebSocket () {let url = 'ws://localhost:8086/demo/websocket/testsocket'this.websocket = new WebSocket(url)// 連接錯(cuò)誤this.websocket.onerror = this.setErrorMessage// 連接成功this.websocket.onopen = this.setOnopenMessage// 收到消息的回調(diào)this.websocket.onmessage = this.setOnmessageMessage// 連接關(guān)閉的回調(diào)this.websocket.onclose = this.setOncloseMessage// 監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。window.onbeforeunload = this.onbeforeunload},reconnect () { // 重新連接if(this.lockReconnect) return;this.lockReconnect = true;//沒連接上會(huì)一直重連,設(shè)置延遲避免請求過多this.timeoutnum && clearTimeout(this.timeoutnum);this.timeoutnum = setTimeout(() => {//新連接this.initWebSocket();this.lockReconnect = false;}, 5000);},reset () { // 重置心跳// 清除時(shí)間clearTimeout(this.timeoutObj);clearTimeout(this.serverTimeoutObj);// 重啟心跳this.start();},start () { // 開啟心跳this.timeoutObj && clearTimeout(this.timeoutObj);this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);this.timeoutObj = setTimeout(() => {// 這里發(fā)送一個(gè)心跳,后端收到后,返回一個(gè)心跳消息,if (this.websocket && this.websocket.readyState == 1) { // 如果連接正常this.websocketsend('heartbeat');} else { // 否則重連this.reconnect();}this.serverTimeoutObj = setTimeout(() => {//超時(shí)關(guān)閉this.websocket.close();}, this.timeout);}, this.timeout)},setOnmessageMessage (event) {let obj = JSON.parse(event.data);console.log("obj",obj)switch(obj.type) {case 'heartbeat'://收到服務(wù)器信息,心跳重置this.reset();break;case 'sendMessage':this.data = obj.dataconsole.log("接收到的服務(wù)器消息:",obj.data)}},setErrorMessage () {//重連this.reconnect();console.log("WebSocket連接發(fā)生錯(cuò)誤" + ' 狀態(tài)碼:' + this.websocket.readyState)},setOnopenMessage () {//開啟心跳this.start();console.log("WebSocket連接成功" + ' 狀態(tài)碼:' + this.websocket.readyState)},setOncloseMessage () {//重連this.reconnect();console.log( "WebSocket連接關(guān)閉" + ' 狀態(tài)碼:' + this.websocket.readyState)},onbeforeunload () {this.closeWebSocket();},//websocket發(fā)送消息websocketsend(messsage) {this.websocket.send(messsage)},closeWebSocket() { // 關(guān)閉websocketthis.websocket.close()},}
}
</script>
6、啟動(dòng)項(xiàng)目開始測試結(jié)果
?7、vue文件連接websocket的url地址要拼接 context-path: /demo