1)WebSocket介绍 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
3)WebSocket数据帧的介绍web
a)、草案版本00到草案版本05之间,详细能够查看草案文档,解码编码能够看见Netty的WebSocketFrameDecoder和WebSocketFrameEncoder实现;apache
b)、草案版本06到如今最新的草案17,介绍参见文章:http://blog.csdn.net/fenglibing/article/details/6852497后端
4)WebSocket不一样版本的几种握手方式
a)、无安全key、最老的WebSocket握手协议的实现(Flash);
b)、带两个安全key请求头的后端握手实现;
c)、带一个安全key请求头的后端握手实现;
参见:http://blog.csdn.net/fenglibing/article/details/7100070
5)WebSocket能够穿越防火墙吗?
WebSocket使用标准的80及443端口,这两个都是防火墙友好协议,Web Sockets使用HTTP Upgrade机制升级到Web Socket协议。HTML5 Web Sockets有着兼容HTTP的握手机制,所以HTTP服务器能够与WebSocket服务器共享默认的HTTP与HTTPS端(80和443)。
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客户端有Firefox4、Chrome4、Opera10.70以及Safari5等,android手机上的webkit等支持html5的都支持,在客户端除了直接使用websocket的api也可使用jquery.socket.jsatmosphere.js socket.io等
Java服务器支持webSocket有tomcat 7.0.27, Netty 3.3.x,Jetty 7.x,GlassFish 3.1.2,比她们更高的版本固然也支持了。
基于HTML5和Tomcat 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版本库见截图
