1)WebSocket介绍
HTML5 Web Sockets规范定义了Web Sockets API,支持页面使用Web Socket协议与远程主机进行全双工的通信。它引入了WebSocket接口并且定义了一个全双工的通信通道,通过一个单一的套接字在Web上进行操作。HTML5 Web Sockets以最小的开销高效地提供了Web连接。相较于经常需要使用推送实时数据到客户端甚至通过维护两个HTTP连接来模拟全双工连接的旧的轮询或长轮询(Comet)来说,这就极大的减少了不必要的网络流量与延迟。
要使用HTML5 Web Sockets从一个Web客户端连接到一个远程端点,你要创建一个新的WebSocket实例并为之提供一个URL来表示你想要连接到的远程端点。该规范定义了ws://以及wss://模式来分别表示WebSocket和安全WebSocket连接。一个WebSocket连接是在客户端与服务器之间HTTP协议的初始握手阶段将其升级到Web Socket协议来建立的,其底层仍是TCP/IP连接。
2)优点
a)、服务器与客户端之间交换的标头信息很小,大概只有2字节;
b)、客户端与服务器都可以主动传送数据给对方;
c)、不用频率创建TCP请求及销毁请求,减少网络带宽资源的占用,同时也节省服务器资源;
3)WebSocket数据帧的介绍
a)、草案版本00到草案版本05之间,详细可以查看草案文档,解码编码可以看见Netty的WebSocketFrameDecoder和WebSocketFrameEncoder实现;
b)、草案版本06到现在最新的草案17,介绍参见文章:
4)WebSocket不同版本的几种握手方式a)、无安全key、最老的WebSocket握手协议的实现(Flash);b)、带两个安全key请求头的后端握手实现;c)、带一个安全key请求头的后端握手实现;
参见:
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连接在存在透明代理服务器的情况下成功的机率会比较大;
关于代理详细参见:
WebSocket,并非HTML 5独有,WebSocket是一种协议。只是在handshake的时候,发送的链接信息头和HTTP相似。HTML 5只是实现了WebSocket的客户端。其实,难点在于服务端,服务端相对还是比较复杂的。
![](https://images0.cnblogs.com/blog/272948/201308/08154709-9931a906828e4b9f97e37fdcae427f4a.jpg)
websocket 的协议在RFC6455中
![](https://images0.cnblogs.com/blog/272948/201308/08154951-1382a2832dc347688fdba7a285b897b4.jpg)
目前支持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库,包含 and ,具体见链接 。
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版本库见截图
![](https://images0.cnblogs.com/blog/272948/201308/08161540-b4df9b6b3d334d6983d50bcd98d3a82c.jpg)