您的位置:首页 > 理论基础 > 计算机网络

【网络协议】Websocket 一

2019-01-05 15:52 155 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_33947548/article/details/85855678

本文原地址https://www.dyzhello.club/static/page/readArticle.html?id=15449

原创内容转载请注明

在web端我们常用http来和服务端通信,那为什么我们还需要websocket呢?其实就是为了解决两个问题:

  1. 实现双向同时通信(全双工通信)
  2. 降低频繁建立连接的开销

websocket和http有什么区别?

  • websocket是建立在http基础上的,我们来看一下两个协议的报文有何异同?

首先我们需要写一段代码来展示请求报文:

java代码:

[code]public class ReadRequest {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = null;
while ((str = reader.readLine()) != null) {
System.out.println(str);
}
}
}

js代码:

[code]if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8080/");
socket.onopen = function (e) {
console.log("connect!");
};
socket.onclose = function (e) {
console.log("close!");
};
socket.onmessage = function (ev) {
console.log(ev);
};
} else {
console.log("不支持");
}

打印结果如下:

Cache-Control: no-cache

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36

Upgrade: websocket

Origin: http://localhost:63342

Sec-WebSocket-Version: 13

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cookie: Idea-cbabd726=27ec50b6-e0fc-4ffd-82e8-35f7213c6787; _ga=GA1.1.1994311309.1541503872; Hm_lvt_8875c662941dbf07e39c556c8d97615f=1544408946; ___rl__test__cookies=1545710196688

Sec-WebSocket-Key: RHduUYcpSAevgb+6ndNR2A==

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

这时候我们看到了websocke请求的报文内容,接下来对比一下不同的http请求,重新启动我们的java代码在浏览器输入:localhost:8080

打印结果如下:

Connection: keep-alive

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cookie: Idea-cbabd726=27ec50b6-e0fc-4ffd-82e8-35f7213c6787; _ga=GA1.1.1994311309.1541503872; Hm_lvt_8875c662941dbf07e39c556c8d97615f=1544408946; ___rl__test__cookies=1545710196688

这个时候我们可以看到相比于http协议websocket多了几行,我们重点看下面这两行:

Upgrade: websocket

可以看到这个时候报文中明确表明了这是一个要升级的协议而且我要升级到websocket

Sec-WebSocket-Key: RHduUYcpSAevgb+6ndNR2A==

这是客户端随机生成的一串字符串用来和服务器进行握手校验

接下来服务器需要发送一个应答包来和客户端进行握手

接着来完成我们的java程序:

[code]public class ReadRequest {
public static String RL = "\r\n";

public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
// 监听8080
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept(); // 等待连接
//        获取输入输出流
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String str = null;
String key = "";
StringBuilder sb = new StringBuilder();
while ((str = reader.readLine()) != null) {
// 发现请求为websocket握手请求
if (str.contains("Sec-WebSocket-Key")) {
String[] strs = str.split(":");
System.out.println(strs[1].trim());
key = strs[1].trim();
//                发送websocket握手包
response(key, writer);
break;
}
sb.append(str + "\r\n");
}
}

/**
* 生成响应并发送
* 生成过程:
* 1.拼接key和固定字符串
* 2.sha-1加密ps:加密过程以及算法本文不做研究
* 3.拼接响应
* 4.返回响应
* @param key
* @param writer
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static void response(String key,Writer writer) throws IOException, NoSuchAlgorithmException {
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
//通过SHA-1算法进行更新
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(key.getBytes("utf-8"), 0, key.length());
byte[] sha1Hash = md.digest();
//进行Base64加密
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
key = encoder.encode(sha1Hash);
StringBuilder responseSb = new StringBuilder();
responseSb.append("HTTP/1.1 101 Switching Protocols").append(RL)
.append("Upgrade: websocket").append(RL) // 必填且为固定应答
.append("Connection: Upgrade").append(RL)
.append("Sec-WebSocket-Accept: " + key).append(RL) //将生成的加密字符串返回
.append("Sec-WebSocket-Version: 13").append(RL)
.append(RL);
writer.write(responseSb.toString());
writer.flush();
}
[code]}我们来看看js打印了什么

connect!

close!

回头看我们的js代码

[code]socket.onopen = function (e) {
console.log("connect!");
};

这的意思是当打开链接打印connect!

也就是说我们的握手成功了!

后续我们将建立功能更加完善的服务端程序,本文到此结束谢谢阅读!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: