【网络协议】Websocket 一

1 篇文章 0 订阅
1 篇文章 0 订阅

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

原创内容转载请注明

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

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

websocket和http有什么区别?

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

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

java代码:

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代码:

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程序:

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();
    }
}我们来看看js打印了什么

connect!

close!

回头看我们的js代码

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值