摘要:收到包后,向發送一個值為,該包發送完成后,和均進入狀態。非強制壓縮發送。因此也就誕生了一個新的通信協議協議,一種全雙工通信協議。會發起一個握手的請求,請求首部含有還有其他首部,具體看如下示例。服務器端返回一個狀態碼,確認轉換協議。
首先說明:這里的tomcat用的是tomcat8.0.36,并不適合tomcat7以及以下版本,(沒辦法websocket的api一直在變,到8之后貌似穩定下來了)
websocket也是html5的新增加內容之一,號稱是下一代客戶端/服務器異步通信辦法,私以為雖然有點吹牛的成分,但是以后說不定能成為異步通信的半壁江山,至于取代ajax,我覺的應該不會
websocket的一個很有意思的特點就是雙向通信,這一點其實也不稀奇,跟socket一樣的。
我記得大二上學期的java課程設計我做的是一個仿照QQ的用戶程序socket通信,寫起來雖然順暢但是因為那個c/s架構寫起來痛苦不已,只實現一個簡單的群聊就要大概一千五的代碼量,尤其回調函數跟界面綁定的時候,寫起來很X痛,從此就再沒寫過windows界面程序
下邊是websocket的原理性知識總結是寫給我自己看的,如果你沒興趣,可以跳過直接到代碼:
tcp建立連接
tcp連接的建立需要經歷”三次握手“的過程。過程如下client發送SYN包(值為j)以及SEQ包到server端,此時client進入SYN_SEND狀態。此為第一次握手。server端收到SYN包后,發送一個ACK(值為seq+1)確認包和SYN(值為k)給client,此時server進入SYN_RECV狀態。此為第二次握手。client收到SYN+ACK包后,向server發送一個ACK(值為k+1),該包發送完成后,client和server均進入ESTABLISH狀態。此為第三次握手。
client和server兩端狀態變化如下:
client:
CLOSED->SYN_SEND->ESTABLISH
server:
CLOSED->LISTEN->SYN_RECV->ESTABLISH
tcp連接釋放
Tcp釋放連接的過程需要經歷“四次揮手”的過程,為什么建立連接只需要3次握手,而釋放連接需要進行4次揮手呢?很簡單,因為TCP連接是全雙工(Full Duplex)的,因此造成了兩個方向都需要進行關閉。怎么理解呢?client和server,需要關閉連接,此時client通知server我要關閉連接了,此時關閉的只會是client這一端的連接,而server端并未關閉,它依舊能夠向client發送數據。當然,關閉連接也可以是server作為主動方的。接下來以client主動斷開與server端的連接為場景來描述整個過程,我們把它分為兩個階段,分別為client端關閉連接和server端關閉連接。
第一階段 首先client會發送一個FIN包給server(同時還有ack和seq包),這是要告訴server,我已經沒有數據要發給你了,此時client處于FIN_WAIT_1狀態。接收到FIN包的server處于CLOSE_WAIT的狀態。 server發回一個ACK(值為client傳過來的seq+1)和seq(值為client傳過來的ack的值)給client。client收到server發過來的包后確認關閉連接,此時client處于FIN_WAIT_2。 第二階段 server在接收到client的FIN后,得知client要斷開tcp連接了,于是在發送完ack和seq給client后,自己發送一個FIN包給client(也帶有ack和seq包),告訴client我也要斷開連接了,此時server處于LAST_ACK狀態。 client接收到server的FIN信息后,會回復server一個ack包,并且會進入TIME_WAIT狀態,持續2個MSL(Max Segment Lifetime),這個時間windows下為240s。而server接收到client后便關閉連接。client在指定時間過后仍然沒有接收到server的數據,確認server已經沒有數據過來,也關閉了連接。 此時雙方都進入CLOSED狀態。
建立細節
tcp是傳輸層的協議,tcp三次握手后,應用層協議http也便建立了連接。而對于當今web的發展情況,http仍有許多瓶頸。
一條連接只能發送一個請求。 請求只能從客戶端開始。客戶端不可以接收除響應以外的指令。 請求/響應首部未經壓縮發送,首部信息越多延遲越大。 發送冗長的首部。每次互相發送相同的首部造成較多的浪費。 可任意選擇數據壓縮格式。非強制壓縮發送。 雖然已經出現了很多解決方案,如ajax、comet,但是他們最終使用的都是http協議,因此也無法從根本上解決這些瓶頸。
因此也就誕生了一個新的通信協議,WebSocket協議,一種全雙工通信協議。
該通信協議建立在http協議的基礎之上,因此連接的發起方仍然是客戶端,在http連接建立之后,再將協議升級為webSocket連接,在webSocket連接建立之后,客戶度和服務器端都可以主動向對方發送報文信息了。
建立webSocket連接,需要先建立http連接,并在此基礎上再進行一次”握手“。
client會發起一個”握手“的請求,請求首部含有upgrade:websocket(還有其他首部,具體看如下示例)。服務器端返回一個101狀態碼,確認轉換協議。完成握手后便可以使用websocket協議進行通信。
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這個協議涉及前端顯示,以及服務器處理,我這里使用基礎的java+js來實現一個簡單的群聊
如果不熟悉websocket的api,你可以看這里:https://developer.mozilla.org...
以及:https://www.ibm.com/developer...
重要的只有兩個文件: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(){ } /* * 打開連接 */ @OnOpen public void onOpen(Session session,@PathParam(value="nickName") String nickName){ this.session=session; this.nickName=nickName; connections.add(this); System.out.println("新用戶連接進入,名字是:"+this.nickName); String message=String.format("System>%s %s",this.nickName,"hasjoined."); Chat.broadCast(message); } /* * 關閉連接 */ @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); } /* * 錯誤消息 */ @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
一些問題:
WebSockets 簡介:將套接字引入網絡
WebSocket 是什么原理?為什么可以實現持久連接?(看尤雨溪大神的回答)
再談應用環境下的TIME_WAIT和CLOSE_WAIT
如果你熟悉nodejs你還可以:
使用Node.js+Socket.IO搭建WebSocket實時應用
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91000.html
摘要:收到包后,向發送一個值為,該包發送完成后,和均進入狀態。非強制壓縮發送。因此也就誕生了一個新的通信協議協議,一種全雙工通信協議。會發起一個握手的請求,請求首部含有還有其他首部,具體看如下示例。服務器端返回一個狀態碼,確認轉換協議。 首先說明:這里的tomcat用的是tomcat8.0.36,并不適合tomcat7以及以下版本,(沒辦法websocket的api一直在變,到8之后貌似穩定...
摘要:早期的輪詢是通過不斷自動刷新頁面而實現的。長輪詢的另一個問題是缺乏標準實現。服務器端接到這個請求后作出回應并不斷更新連接狀態以保證客戶端和服務器端的連接不過期。協議解析協議包含兩部分一部分是握手,一部分是數據傳輸。 Websocket是什么? Websocket是一個因為應用場景越來越復雜而提出的,針對瀏覽器和web服務器之間雙向持續通信而設計,而且優雅地兼容HTTP的協議(我猜想:同...
摘要:官網地址聊天機器人插件開發實例教程一創建插件在系統技巧使你的更加專業前端掘金一個幫你提升技巧的收藏集。我會簡單基于的簡潔視頻播放器組件前端掘金使用和實現購物車場景前端掘金本文是上篇文章的序章,一直想有機會再次實踐下。 2道面試題:輸入URL按回車&HTTP2 - 掘金通過幾輪面試,我發現真正那種問答的技術面,寫一堆項目真不如去刷技術文章作用大,因此刷了一段時間的博客和掘金,整理下曾經被...
閱讀 955·2023-04-25 23:50
閱讀 1954·2021-11-19 09:40
閱讀 598·2019-08-30 13:50
閱讀 2727·2019-08-29 17:11
閱讀 1041·2019-08-29 16:37
閱讀 2985·2019-08-29 12:54
閱讀 2792·2019-08-28 18:17
閱讀 2636·2019-08-26 16:55