WebSocket 學習體會
WebSocket,并非HTML 5獨有,WebSocket是一種協議。只是在handshake的時候,發送的鏈接信息頭和HTTP相似。HTML 5只是實現了WebSocket的客戶端。其實,難點在于服務端,服務端相對還是比較復雜的。
網上demo很多,但是能講到點上的不多,而且也不知道作者有沒有深入試驗過。WebSokect協議 ,handshake這part其實還是比較簡單的,比較復雜的還是數據傳輸(第二部分)比較難。
上圖是幀格式,對于解釋可以看文檔也可以查看文章:http://www.cnblogs.com/imayi/archive/2012/05/05/2485343.html
也就說,你需要解讀opcode, Payload len 這些比較敏感的位值之后,你才開始取后面的Payload Data, 比如opcode如果是1,那么就是讀取字符串,如果是2,那么就是讀取流。
如果自己用java做服務端,握手協議的響應,換行符不能使“\r\n”或“\n”,因為這不是標準的換行符,其實是個字符串,只是屏幕顯示的時候是換行,可以用PrintWrite.println(),或者
String newLine = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
握手之后,根據opcode做相應的操作,JAVA的IO和NIO,在實現方面都缺憾,難以實現。使用IO的話,在獲得socket之 后,InputStream會處于阻塞,因為阻塞,所以后續做outputStream的操作時就會不方便。NIO的話,是SocketChannel寫 入讀出,基本都是ByteBuffer,用這個的話,有時opcode值為1(讀取字符串),ByteBuffer解碼得到的字符串經常性是亂碼。感覺最 好還是學Tomcat,自己重寫一下InputStream。
Tomcat在7.0.27之后就開始支持WebSocket,在它之上建立WebSocket是很簡單的,基本就是繼承 WebSocketServlet,實現createWebSocketInbound方法和重寫StreamInbound的方法。Tomcat的 example里面有相關的例子。
Tomcat處理流程,WebSocketServlet本身就繼承了HttpServlet,重寫doGet方法,在doGet方法里面做了 handshake的操作,之后就是一些UpgradeInbound的操作,做好接收數據流的準備(StreamInbound提供了onData方 法)。每次數據過來,都會執行onData里面的WsFrame frame = wsIs.nextFrame(true); 對數據幀進行分析,并且提供自定義InputStream流,調用用戶重寫的onBinaryData或者onTextData方法,將輸入流里面的數據 讀出,再response給客戶端。
WebSocketServlet(doGet) -> handshake -> createWebSocketInbound -> doUpgrade -> setUpgradeProcessor ->
onUpgradeComplete -> onData -> 數據過來 -> wsIs.nextFrame(true) -> 生成自定義InputStream -> 調用用戶重寫方法 (另外如果opcode是關閉Socket,也會有相應的操作)