websocket學習和使用

1WebSocket介紹 javascript

HTML5 Web Sockets規範定義了Web Sockets API,支持頁面使用Web Socket協議與遠程主機進行全雙工的通訊。它引入了WebSocket接口而且定義了一個全雙工的通訊通道,經過一個單一的套接字在Web上進行操做。HTML5 Web Sockets以最小的開銷高效地提供了Web鏈接。相較於常常須要使用推送實時數據到客戶端甚至經過維護兩個HTTP鏈接來模擬全雙工鏈接的舊的輪詢或長輪詢(Comet)來講,這就極大的減小了沒必要要的網絡流量與延遲。css

要使用HTML5 Web Sockets從一個Web客戶端鏈接到一個遠程端點,你要建立一個新的WebSocket實例併爲之提供一個URL來表示你想要鏈接到的遠程端點。該規範定義了ws://以及wss://模式來分別表示WebSocket和安全WebSocket鏈接。一個WebSocket鏈接是在客戶端與服務器之間HTTP協議的初始握手階段將其升級到Web Socket協議來創建的,其底層還是TCP/IP鏈接。 html

2)優勢 html5

a)、服務器與客戶端之間交換的標頭信息很小,大概只有2字節;java

b)、客戶端與服務器均可以主動傳送數據給對方;jquery

c)、不用頻率建立TCP請求及銷燬請求,減小網絡帶寬資源的佔用,同時也節省服務器資源;android

 3WebSocket數據幀的介紹web

a)、草案版本00到草案版本05之間,詳細能夠查看草案文檔,解碼編碼能夠看見NettyWebSocketFrameDecoderWebSocketFrameEncoder實現;apache

b)、草案版本06到如今最新的草案17,介紹參見文章:http://blog.csdn.net/fenglibing/article/details/6852497後端

4WebSocket不一樣版本的幾種握手方式
a
)、無安全key、最老的WebSocket握手協議的實現(Flash);
b
)、帶兩個安全key請求頭的後端握手實現;
c
)、帶一個安全key請求頭的後端握手實現;

參見:http://blog.csdn.net/fenglibing/article/details/7100070

5WebSocket能夠穿越防火牆嗎?

WebSocket使用標準的80443端口,這兩個都是防火牆友好協議,Web Sockets使用HTTP Upgrade機制升級到Web Socket協議。HTML5 Web Sockets有着兼容HTTP的握手機制,所以HTTP服務器能夠與WebSocket服務器共享默認的HTTPHTTPS端(80443)。

6)、Web Sockets與代理服務器交互
代理服務器的問題:
a
)、HTTP代理服務器可能會選擇關閉流或閒置的WebSocket鏈接,由於它們看起好像是嘗試鏈接一個沒有迴應的HTTP服務器;
b
)、代理服務器可能會緩衝未加密的HTTP響應,這將會對HTTP響應流帶來不可估計的延遲;
c
)、未加密的WebSocket鏈接(ws://開頭的請求)服務器時,若是中間存在透明代理服務器,鏈接可能會失敗,或者發送消息會失敗;而加密的WebSocket鏈接在存在透明代理服務器的狀況下成功的機率會比較大;

關於代理詳細參見:http://www.infoq.com/cn/articles/Web-Sockets-Proxy-Servers 

 

WebSocket,並不是HTML 5獨有,WebSocket是一種協議。只是在handshake的時候,發送的連接信息頭和HTTP類似。HTML 5只是實現了WebSocket的客戶端。其實,難點在於服務端,服務端相對仍是比較複雜的。 

 

websocket 的協議在RFC6455中  http://tools.ietf.org/html/rfc6455#section-5.1

 

目前支持webSocket客戶端有Firefox4Chrome4Opera10.70以及Safari5等,android手機上的webkit等支持html5的都支持,在客戶端除了直接使用websocketapi也可使用jquery.socket.jsatmosphere.js socket.io

Java服務器支持webSockettomcat 7.0.27, Netty 3.3.x,Jetty 7.x,GlassFish 3.1.2,比她們更高的版本固然也支持了。

基於HTML5Tomcat WebSocketServlet以及android聊天室簡單實現  

index.jsp 

<%@ page language= " java " contentType= " text/html; charset=UTF-8 "
    pageEncoding= " UTF-8 " %>
<%
     String path = request.getContextPath();
     String WsBasePath =  " ws:// " + request.getServerName() +  " : "
            + request.getServerPort() + path +  " / ";
%>
< html >
< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=UTF-8" >
< title >websocket聊天室 </ title >
< style  type ="text/css" >
#chat 
{
    text-align
:  left;
    width
:  600px;
    height
:  500px;
    width
:  600px;
}

#up 
{
    text-align
:  left;
    width
:  100%;
    height
:  400px;
    border
:  1px solid green;
    OVERFLOW-Y
:  auto;
}

#down 
{
    text-align
:  left;
    height
:  100px;
    width
:  100%;
}
</ style >
</ head >
< body >
     < h2  align ="center" >基於HTML5的聊天室 </ h2 >
     < div  align ="center"  style ="width: 100%; height: 700px;" >
         < div  id ="chat" >
             < div  id ="up" ></ div >
             < div  id ="down" >
                 < textarea  style ="width: 602px; height: 100%;"  id ="send" ></ textarea >
             </ div >
         </ div >
         < br />
         < input  type ="button"  value ="鏈接"  onclick ="chat(this);" >  < input
            
type ="button"  value ="發送"  onclick ="send(this);"  disabled ="disabled"
            id
="send_btn"  title ="Ctrl+Enter發送" >
     </ div >
</ body >
< script  type ="text/javascript" >
     var socket;
     var receive_text = document.getElementById("up");
     var send_text = document.getElementById("send");
     function addText(msg) {
        receive_text.innerHTML += "<br/>" + msg;
        receive_text.scrollTop = receive_text.scrollHeight;
    }
     var chat =  function(obj) {
        obj.disabled = "disabled";
         try{
            socket =  new WebSocket('<%=WsBasePath + "chat"%>');
            receive_text.innerHTML += '<%=WsBasePath + "chat"%>';
            receive_text.innerHTML += "<font color=green>正在鏈接服務器……</font>";
        } catch(e){
            receive_text.innerHTML += "<font color=red>抱歉,您的瀏覽器不支持html5,請使用IE10或者最新版本的谷歌、火狐等瀏覽器!</font>";
        }
         // 打開Socket 
        socket.onopen =  function(event) {
            falg= false;
            addText("<font color=green>鏈接成功!</font>");
            document.getElementById("send_btn").disabled =  false;
            send_text.focus();
            document.onkeydown =  function(event) {
                 if (event.keyCode == 13 && event.ctrlKey) {
                    send();
                }
            };
        };
        socket.onmessage =  function(event) {
            addText(event.data);
        };

        socket.onclose =  function(event) {
            addText("<font color=red>鏈接斷開!</font>");
            obj.disabled = "";
        };
    };
     var send =  function(obj) {
         if (send_text.value == "") {
             return;
        }
        socket.send(send_text.value);
        send_text.value = "";
        send_text.focus();
    };
</ script >
</ html >

 

ChatWebSocketServlet.java 

 


import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
import org.apache.catalina.websocket.WsOutbound;

@WebServlet("/chat")
public  class ChatWebSocketServlet  extends WebSocketServlet {

     private  final Map<Integer, WsOutbound> map =  new HashMap<Integer, WsOutbound>();
     // private static final long serialVersionUID = -1058445282919079067L;
     private  static  final  long serialVersionUID = 911879078000755859L;

     public  class ChatMessageInbound  extends MessageInbound {

        @Override
         protected  void onBinaryMessage(ByteBuffer arg0)  throws IOException {
             //  TODO Auto-generated method stub

        }

        @Override
         protected  void onTextMessage(CharBuffer arg0)  throws IOException {
             //  TODO Auto-generated method stub
            String msg = arg0.toString();
            Date date =  new Date();
            SimpleDateFormat sdf =  new SimpleDateFormat("HH:mm:ss");
            msg = " <font color=green>匿名用戶  " + sdf.format(date) + "</font><br/> " + msg;
            broadcast(msg);
        }

        @Override
         protected  void onClose( int status) {
             //  TODO Auto-generated method stub
            map.remove(getWsOutbound().hashCode());
             super.onClose(status);
        }

        @Override
         protected  void onOpen(WsOutbound outbound) {
             //  TODO Auto-generated method stub
            map.put(outbound.hashCode(), outbound);
            System.out.println("上線" + outbound.hashCode());
             super.onOpen(outbound);
        }

    }

    @Override
     protected StreamInbound createWebSocketInbound(String arg0,
            HttpServletRequest arg1) {
         //  TODO Auto-generated method stub
         return  new ChatMessageInbound();
    }

     private  void broadcast(String msg) {
        Set<Integer> set = map.keySet();
         for (Integer integer : set) {
            WsOutbound outbound = map.get(integer);
            CharBuffer buffer = CharBuffer.wrap(msg);
             try {
                outbound.writeTextMessage(buffer);
                outbound.flush();
            }  catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}


基於android客戶端和websocket協議實現的有autobahn庫,包含The WebSocket Protocol and The WebSocket Application Messaging Protocol (WAMP),具體見連接 http://autobahn.ws/android

 package com.example.testwebsocket;



import de.tavendo.autobahn.WebSocketConnection;
import de.tavendo.autobahn.WebSocketConnectionHandler;
import de.tavendo.autobahn.WebSocketException;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public  class MainActivity  extends Activity {

    @Override
     protected  void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.out.println("開始鏈接websocket///");
         final WebSocketConnection wsc =  new WebSocketConnection();
         try {
            wsc.connect(
                    "ws://10.204.79.19:8080/chat",
                     new WebSocketConnectionHandler() {

                        @Override
                         public  void onOpen() {
                             //  TODO Auto-generated method stub
                            System.out.println("onOpen");
                            wsc.sendTextMessage("Hello!");
                             // wsc.disconnect();
                            
//  super.onOpen();
                        }

                        @Override
                         public  void onClose( int code, String reason) {
                             //  TODO Auto-generated method stub
                            System.out.println("onClose reason=" + reason);
                             //  super.onClose(code, reason);
                        }

                        @Override
                         public  void onTextMessage(String payload) {
                             //  TODO Auto-generated method stub
                            System.out.println("onTextMessage" + payload);
                             //  super.onTextMessage(payload);
                        }

                        @Override
                         public  void onRawTextMessage( byte[] payload) {
                             //  TODO Auto-generated method stub
                            System.out.println("onRawTextMessage size="
                                    + payload.length);
                             //  super.onRawTextMessage(payload);
                        }

                        @Override
                         public  void onBinaryMessage( byte[] payload) {
                             //  TODO Auto-generated method stub
                            System.out.println("onBinaryMessage size="
                                    + payload.length);
                             //  super.onBinaryMessage(payload);
                        }

                    });
        }  catch (WebSocketException e) {
            e.printStackTrace();
        }

    }

    @Override
     public  boolean onCreateOptionsMenu(Menu menu) {
         //  Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
         return  true;
    }

}

相關websocket協議實現的android版本庫見截圖

相關文章
相關標籤/搜索