【网络协议】Websocket 一
本文原地址https://www.dyzhello.club/static/page/readArticle.html?id=15449
原创内容转载请注明
在web端我们常用http来和服务端通信,那为什么我们还需要websocket呢?其实就是为了解决两个问题:
- 实现双向同时通信(全双工通信)
- 降低频繁建立连接的开销
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!
也就是说我们的握手成功了!
后续我们将建立功能更加完善的服务端程序,本文到此结束谢谢阅读!
- 浅析H5中的WebSocket对象,创建 一个基于node的TCP网络协议的通讯协议
- Websocket一个持久化网络通信的协议
- 游戏网络编程(三)——WebSocket入门及实现自己的WebSocket协议
- Cocos2d中的网络通信协议(Socket通讯,http协议,WebSocket协议)
- WebSocket 网络通信协议
- wareshark网络协议分析之DHCP
- 前端开发过程中的网络传输协议
- 常见网络协议简单介绍
- 常用的 网络协议 端口号 总结
- Linux 网络协议栈之内核锁(七)—— 读写自旋锁
- Android最佳实践——深入浅出WebSocket协议
- 网络编程和TC协议
- CocoaAsyncSocket 网络通信使用之http协议测试(三)
- 常见网络通信协议结构图
- 网络协议格式(二)
- iOS网络协议篇
- [计算机网络] TCP协议与UDP协议的区别
- 网络协议篇
- 【网络编程系列1】网络协议
- 网络协议重新认识