摘要:收到包后,向發(fā)送一個(gè)值為,該包發(fā)送完成后,和均進(jìn)入狀態(tài)。非強(qiáng)制壓縮發(fā)送。因此也就誕生了一個(gè)新的通信協(xié)議協(xié)議,一種全雙工通信協(xié)議。會(huì)發(fā)起一個(gè)握手的請(qǐng)求,請(qǐng)求首部含有還有其他首部,具體看如下示例。服務(wù)器端返回一個(gè)狀態(tài)碼,確認(rèn)轉(zhuǎn)換協(xié)議。
首先說(shuō)明:這里的tomcat用的是tomcat8.0.36,并不適合tomcat7以及以下版本,(沒(méi)辦法websocket的api一直在變,到8之后貌似穩(wěn)定下來(lái)了)
websocket也是html5的新增加內(nèi)容之一,號(hào)稱(chēng)是下一代客戶(hù)端/服務(wù)器異步通信辦法,私以為雖然有點(diǎn)吹牛的成分,但是以后說(shuō)不定能成為異步通信的半壁江山,至于取代ajax,我覺(jué)的應(yīng)該不會(huì)
websocket的一個(gè)很有意思的特點(diǎn)就是雙向通信,這一點(diǎn)其實(shí)也不稀奇,跟socket一樣的。
我記得大二上學(xué)期的java課程設(shè)計(jì)我做的是一個(gè)仿照QQ的用戶(hù)程序socket通信,寫(xiě)起來(lái)雖然順暢但是因?yàn)槟莻€(gè)c/s架構(gòu)寫(xiě)起來(lái)痛苦不已,只實(shí)現(xiàn)一個(gè)簡(jiǎn)單的群聊就要大概一千五的代碼量,尤其回調(diào)函數(shù)跟界面綁定的時(shí)候,寫(xiě)起來(lái)很X痛,從此就再?zèng)]寫(xiě)過(guò)windows界面程序
下邊是websocket的原理性知識(shí)總結(jié)是寫(xiě)給我自己看的,如果你沒(méi)興趣,可以跳過(guò)直接到代碼:
tcp建立連接
tcp連接的建立需要經(jīng)歷”三次握手“的過(guò)程。過(guò)程如下client發(fā)送SYN包(值為j)以及SEQ包到server端,此時(shí)client進(jìn)入SYN_SEND狀態(tài)。此為第一次握手。server端收到SYN包后,發(fā)送一個(gè)ACK(值為seq+1)確認(rèn)包和SYN(值為k)給client,此時(shí)server進(jìn)入SYN_RECV狀態(tài)。此為第二次握手。client收到SYN+ACK包后,向server發(fā)送一個(gè)ACK(值為k+1),該包發(fā)送完成后,client和server均進(jìn)入ESTABLISH狀態(tài)。此為第三次握手。
client和server兩端狀態(tài)變化如下:
client:
CLOSED->SYN_SEND->ESTABLISH
server:
CLOSED->LISTEN->SYN_RECV->ESTABLISH
tcp連接釋放
Tcp釋放連接的過(guò)程需要經(jīng)歷“四次揮手”的過(guò)程,為什么建立連接只需要3次握手,而釋放連接需要進(jìn)行4次揮手呢?很簡(jiǎn)單,因?yàn)門(mén)CP連接是全雙工(Full Duplex)的,因此造成了兩個(gè)方向都需要進(jìn)行關(guān)閉。怎么理解呢?client和server,需要關(guān)閉連接,此時(shí)client通知server我要關(guān)閉連接了,此時(shí)關(guān)閉的只會(huì)是client這一端的連接,而server端并未關(guān)閉,它依舊能夠向client發(fā)送數(shù)據(jù)。當(dāng)然,關(guān)閉連接也可以是server作為主動(dòng)方的。接下來(lái)以client主動(dòng)斷開(kāi)與server端的連接為場(chǎng)景來(lái)描述整個(gè)過(guò)程,我們把它分為兩個(gè)階段,分別為client端關(guān)閉連接和server端關(guān)閉連接。
第一階段 首先client會(huì)發(fā)送一個(gè)FIN包給server(同時(shí)還有ack和seq包),這是要告訴server,我已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)給你了,此時(shí)client處于FIN_WAIT_1狀態(tài)。接收到FIN包的server處于CLOSE_WAIT的狀態(tài)。 server發(fā)回一個(gè)ACK(值為client傳過(guò)來(lái)的seq+1)和seq(值為client傳過(guò)來(lái)的ack的值)給client。client收到server發(fā)過(guò)來(lái)的包后確認(rèn)關(guān)閉連接,此時(shí)client處于FIN_WAIT_2。 第二階段 server在接收到client的FIN后,得知client要斷開(kāi)tcp連接了,于是在發(fā)送完ack和seq給client后,自己發(fā)送一個(gè)FIN包給client(也帶有ack和seq包),告訴client我也要斷開(kāi)連接了,此時(shí)server處于LAST_ACK狀態(tài)。 client接收到server的FIN信息后,會(huì)回復(fù)server一個(gè)ack包,并且會(huì)進(jìn)入TIME_WAIT狀態(tài),持續(xù)2個(gè)MSL(Max Segment Lifetime),這個(gè)時(shí)間windows下為240s。而server接收到client后便關(guān)閉連接。client在指定時(shí)間過(guò)后仍然沒(méi)有接收到server的數(shù)據(jù),確認(rèn)server已經(jīng)沒(méi)有數(shù)據(jù)過(guò)來(lái),也關(guān)閉了連接。 此時(shí)雙方都進(jìn)入CLOSED狀態(tài)。
建立細(xì)節(jié)
tcp是傳輸層的協(xié)議,tcp三次握手后,應(yīng)用層協(xié)議http也便建立了連接。而對(duì)于當(dāng)今web的發(fā)展情況,http仍有許多瓶頸。
一條連接只能發(fā)送一個(gè)請(qǐng)求。 請(qǐng)求只能從客戶(hù)端開(kāi)始??蛻?hù)端不可以接收除響應(yīng)以外的指令。 請(qǐng)求/響應(yīng)首部未經(jīng)壓縮發(fā)送,首部信息越多延遲越大。 發(fā)送冗長(zhǎng)的首部。每次互相發(fā)送相同的首部造成較多的浪費(fèi)。 可任意選擇數(shù)據(jù)壓縮格式。非強(qiáng)制壓縮發(fā)送。 雖然已經(jīng)出現(xiàn)了很多解決方案,如ajax、comet,但是他們最終使用的都是http協(xié)議,因此也無(wú)法從根本上解決這些瓶頸。
因此也就誕生了一個(gè)新的通信協(xié)議,WebSocket協(xié)議,一種全雙工通信協(xié)議。
該通信協(xié)議建立在http協(xié)議的基礎(chǔ)之上,因此連接的發(fā)起方仍然是客戶(hù)端,在http連接建立之后,再將協(xié)議升級(jí)為webSocket連接,在webSocket連接建立之后,客戶(hù)度和服務(wù)器端都可以主動(dòng)向?qū)Ψ桨l(fā)送報(bào)文信息了。
建立webSocket連接,需要先建立http連接,并在此基礎(chǔ)上再進(jìn)行一次”握手“。
client會(huì)發(fā)起一個(gè)”握手“的請(qǐng)求,請(qǐng)求首部含有upgrade:websocket(還有其他首部,具體看如下示例)。服務(wù)器端返回一個(gè)101狀態(tài)碼,確認(rèn)轉(zhuǎn)換協(xié)議。完成握手后便可以使用websocket協(xié)議進(jìn)行通信。
Client(request)
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: AQIDBAUGBwgJCgsMDQ4PEC== Origin: http://example.com Sec-WebSocket-protocol: chat, superchat Sec-WebSocket-Version: 13
server (response)
HTTP/1.1 101 switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Protocol: chat
websocket這個(gè)協(xié)議涉及前端顯示,以及服務(wù)器處理,我這里使用基礎(chǔ)的java+js來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的群聊
如果不熟悉websocket的api,你可以看這里:https://developer.mozilla.org...
以及:https://www.ibm.com/developer...
重要的只有兩個(gè)文件:chat.java以及chat.html
Chat.java:
package example; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value="/ws/chat/{nickName}") public class Chat { private static final Setconnections = new CopyOnWriteArraySet (); private String nickName; private Session session; public Chat(){ } /* * 打開(kāi)連接 */ @OnOpen public void onOpen(Session session,@PathParam(value="nickName") String nickName){ this.session=session; this.nickName=nickName; connections.add(this); System.out.println("新用戶(hù)連接進(jìn)入,名字是:"+this.nickName); String message=String.format("System>%s %s",this.nickName,"hasjoined."); Chat.broadCast(message); } /* * 關(guān)閉連接 */ @OnClose public void onClose(){ connections.remove(this); String message=String.format("System> %s, %s", this.nickName, " has disconnection."); Chat.broadCast(message); } /* * 接收信息 */ @OnMessage public void onMessage(String message,@PathParam(value="nickName")String nickName){ System.out.println("新消息from:"+nickName+" : "+message); Chat.broadCast(nickName+">"+message); } /* * 錯(cuò)誤消息 */ @OnError public void onError(Throwable throwable){ System.out.println(throwable.getMessage()); } /* * 廣播消息 */ private static void broadCast(String message){ for(Chat chat:connections){ try{ synchronized (chat) { chat.session.getBasicRemote().sendText(message); } }catch(IOException e){ connections.remove(chat); try{ chat.session.close(); }catch(IOException e1){ chat.broadCast(String.format("System> %s %s", chat.nickName, " has bean disconnection.")); } } } } }
chat.html:
Testing websockets
一些問(wèn)題:
WebSockets 簡(jiǎn)介:將套接字引入網(wǎng)絡(luò)
WebSocket 是什么原理?為什么可以實(shí)現(xiàn)持久連接?(看尤雨溪大神的回答)
再談應(yīng)用環(huán)境下的TIME_WAIT和CLOSE_WAIT
如果你熟悉nodejs你還可以:
使用Node.js+Socket.IO搭建WebSocket實(shí)時(shí)應(yīng)用
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65159.html
摘要:收到包后,向發(fā)送一個(gè)值為,該包發(fā)送完成后,和均進(jìn)入狀態(tài)。非強(qiáng)制壓縮發(fā)送。因此也就誕生了一個(gè)新的通信協(xié)議協(xié)議,一種全雙工通信協(xié)議。會(huì)發(fā)起一個(gè)握手的請(qǐng)求,請(qǐng)求首部含有還有其他首部,具體看如下示例。服務(wù)器端返回一個(gè)狀態(tài)碼,確認(rèn)轉(zhuǎn)換協(xié)議。 首先說(shuō)明:這里的tomcat用的是tomcat8.0.36,并不適合tomcat7以及以下版本,(沒(méi)辦法websocket的api一直在變,到8之后貌似穩(wěn)定...
摘要:早期的輪詢(xún)是通過(guò)不斷自動(dòng)刷新頁(yè)面而實(shí)現(xiàn)的。長(zhǎng)輪詢(xún)的另一個(gè)問(wèn)題是缺乏標(biāo)準(zhǔn)實(shí)現(xiàn)。服務(wù)器端接到這個(gè)請(qǐng)求后作出回應(yīng)并不斷更新連接狀態(tài)以保證客戶(hù)端和服務(wù)器端的連接不過(guò)期。協(xié)議解析協(xié)議包含兩部分一部分是握手,一部分是數(shù)據(jù)傳輸。 Websocket是什么? Websocket是一個(gè)因?yàn)閼?yīng)用場(chǎng)景越來(lái)越復(fù)雜而提出的,針對(duì)瀏覽器和web服務(wù)器之間雙向持續(xù)通信而設(shè)計(jì),而且優(yōu)雅地兼容HTTP的協(xié)議(我猜想:同...
摘要:官網(wǎng)地址聊天機(jī)器人插件開(kāi)發(fā)實(shí)例教程一創(chuàng)建插件在系統(tǒng)技巧使你的更加專(zhuān)業(yè)前端掘金一個(gè)幫你提升技巧的收藏集。我會(huì)簡(jiǎn)單基于的簡(jiǎn)潔視頻播放器組件前端掘金使用和實(shí)現(xiàn)購(gòu)物車(chē)場(chǎng)景前端掘金本文是上篇文章的序章,一直想有機(jī)會(huì)再次實(shí)踐下。 2道面試題:輸入U(xiǎn)RL按回車(chē)&HTTP2 - 掘金通過(guò)幾輪面試,我發(fā)現(xiàn)真正那種問(wèn)答的技術(shù)面,寫(xiě)一堆項(xiàng)目真不如去刷技術(shù)文章作用大,因此刷了一段時(shí)間的博客和掘金,整理下曾經(jīng)被...
閱讀 1901·2021-11-22 09:34
閱讀 3039·2021-09-28 09:35
閱讀 13474·2021-09-09 11:34
閱讀 3603·2019-08-29 16:25
閱讀 2834·2019-08-29 15:23
閱讀 2048·2019-08-28 17:55
閱讀 2438·2019-08-26 17:04
閱讀 3053·2019-08-26 12:21