暑假在家研究了一下webSocket服务器
首先从webSocket原理讲解。b/s构架是基于http协议,这不是一个长连接,而且也分主动和被动。浏览器主动向服务器发出请求,等待服务器的响应到达,然后断开连接。这种方式的通信非常不适合不如聊天这种功能的实现。为了弥补这个缺陷,浏览器就有了webSocket(web套接字)这种新技术来再现socket(套接字)。但是与socket不同的是,它有发送格式的要求。
建议参考如下文章:WebSocket协议:5分钟从入门到精通
看完上一连接的文章后我对webSocket有了基本的了解,但是还是不太了解握手
接着就看了下面的文章:基于websocket的前端与后端之间的数据交互
知道了握手key的算法
但是还是不了解如何计算长度和获得内容的
于是就有下面这篇文章:WebSocket握手协议
里面有关键的代码,虽然是C/C++写的,但是还是思路是相同的
有了以上的知识储备,我就试着搭建了第一个webSocket服务器,准确的说是含有webSocket成分的服务器。我的目的是建设一个聊天服务器,已经能够在客户端实现,我还想在浏览器上实现,实现两方的三种情况都能通信,这就需要用到webSocket技术,我想在原有服务器的基础上新增几个类,用来将webSocket发来的数据帧转换成能用的格式,事实上确实成功了。
下面附上webSocket的关键代码
JAVA
用来生成握手钥匙(接着就看了下面的文章:基于websocket的前端与后端之间的数据交互)
public static String getWSSecretKey(String strWebSocketKey) {
String MAGIC_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
MessageDigest shaMD = null;
try {
strWebSocketKey = strWebSocketKey + MAGIC_KEY;
shaMD = MessageDigest.getInstance("SHA-1");
shaMD.reset();
shaMD.update(strWebSocketKey.getBytes());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte messageDigest[] = shaMD.digest();
BASE64Encoder b64 = new BASE64Encoder();
return b64.encode(messageDigest);
}
用来和浏览器握手
public static void responseConnection(Socket s) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String result=br.readLine();
String key="";
String skey="";
//!result.contains("\r\n")
while(result.length()>0){
if(result.contains("Sec-WebSocket-Key:")){
key=result.split(": ")[1];
skey=getWSSecretKey(key);
}
System.out.println(result);
result=br.readLine();
}
PrintStream ps=new PrintStream(s.getOutputStream());
ps.println("HTTP/1.1 101 Switching Protocols");
ps.println("Connection: Upgrade");
ps.println("Upgrade: WebSocket");
ps.println(("Sec-WebSocket-Accept: "+skey));
ps.println("Sec-WebSocket-Location: ws://127.0.0.1:8008/");
ps.println();
}
public static void responseConnection(Socket s,BufferedReader br ) throws IOException{
String result=br.readLine();
String key="";
String skey="";
//!result.contains("\r\n")
while(result.length()>0){
if(result.contains("Sec-WebSocket-Key:")){
key=result.split(": ")[1];
skey=getWSSecretKey(key);
}
System.out.println(result);
result=br.readLine();
}
PrintStream ps=new PrintStream(s.getOutputStream());
ps.println("HTTP/1.1 101 Switching Protocols");
ps.println("Connection: Upgrade");
ps.println("Upgrade: WebSocket");
ps.println(("Sec-WebSocket-Accept: "+skey));
ps.println("Sec-WebSocket-Location: ws://127.0.0.1:8008/");
ps.println();
}
用来接收浏览器的数据帧,并且筛选出内容
public static byte[] getWebSocket(Socket s) throws IOException{
InputStream is=s.getInputStream();
byte[] result=null;
int len=0;
while((len=is.read())!=129);
System.out.println("len: "+len);
if(len==129){
if((len=is.read()-128)<=125){
int[] XOR=new int[4];
XOR[0]=is.read();
XOR[1]=is.read();
XOR[2]=is.read();
XOR[3]=is.read();
System.out.println("len: "+len);
result=new byte[len];
for(int i=0;i<len;i++){
int t=is.read();
result[i]=(byte) (t^XOR[i%4]);
System.out.println(t);
}
}else if((len=is.read()-128)==126){
}else if((len=is.read()-128)==127){
}
}else{
System.out.println("len!=129");
return "null".getBytes();
}
System.out.println("getWebSocket: "+new String(result,"UTF-8"));
return result;
}
用来将待发送文本包装成数据帧的格式发送到浏览器
public static void sendWebSocket(Socket s,String result) throws IOException{
byte[] e=null;
if(result.getBytes().length<=125){
//byte[1]低7位表示数据长度,<=125时,后面不跟任何表示长度的字节
e=new byte[]{(byte) 129,(byte) result.getBytes().length};
}else if(result.getBytes().length<=65535){
//byte[1]低7位表示数据长度,125<length<=65535时,后面跟两位表示长度的字节
e=new byte[]{(byte) 129,(byte) 126,(byte) (result.getBytes().length>>8),(byte) result.getBytes().length};
}else{
//byte[1]低7位表示数据长度,65535<length<=8字节时,后面跟4位表示长度的字节
e=new byte[]{(byte) 129,(byte) 127,(byte) (result.getBytes().length>>24),(byte) (result.getBytes().length>>16),(byte) (result.getBytes().length>>8),(byte) result.getBytes().length};
}
s.getOutputStream().write(e);
s.getOutputStream().flush();
s.getOutputStream().write(result.getBytes("UTF-8"));
s.getOutputStream().flush();
}
以上代码并没有考虑到所有情况,没有使用到webSocket的所有功能,仅仅满足了当前的需要,以后有时间一定要补充完整。