WebSocket协议初探

发布时间 2023-11-22 12:05:32作者: 一点意思

1.介绍

历史上在创建一个需要双向通信的web应用需要滥用服务器推送技术通过上流通知。

这样产生三个问题:

  • 服务器被迫使用不同连接数量的TCP连接每个客户端。
  • 这个协议很高的消耗,在每个客户端和服务端交流的数据中有HTTP header。
  • 客户端被迫维持来自外部连接的响应的映射。

websocket协议以及API,通过独立TCP直接连接,用来取代HTTP轮询web页面到服务器。

类似的技术被大量web应用使用在游戏、股市行情、多用户即时通讯等,websocket基于http基础通信上保证效率和可靠之间的平衡.

2.协议

两个部分:握手和数据传输。

客户端握手:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

 服务端握手:

 HTTP/1.1 101 Switching Protocols
 Upgrade: websocket
 Connection: Upgrade
 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
 Sec-WebSocket-Protocol: chat
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Base64;
import java.security.MessageDigest;

public class WebServer {

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        ServerSocket serverSocket = new ServerSocket(8888);
        Socket socket = serverSocket.accept();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
        String line;
        Map<String, String> map = new HashMap<>();

        while (bufferedReader.ready()) {
            line = bufferedReader.readLine();
            System.out.println(line);
            String[] head = line.split(":");
            if (head.length == 2) {
                map.put(head[0], head[1]);
            }
        }
        System.out.println("--------------------");
        //UUID uuid = UUID.fromString("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
        String code = map.get("Sec-WebSocket-Key").substring(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(code.getBytes());
        byte[] key = md.digest();
        printWriter.write("HTTP/1.1 101 Switching Protocols\r\n");
        printWriter.write("Upgrade: websocket\r\n");
        printWriter.write("Connection: Upgrade\r\n");
        printWriter.write("Sec-WebSocket-Accept: " + Base64.getEncoder().encodeToString(key) + " \r\n");
        printWriter.write("\r\n");
        printWriter.flush();
        
    }
}
View Code
描述:在服务器与客户端握手成功后,在传输中通道内的消息由一个或多个帧组成。websocket帧不需要特别的网络帧表示,一般为碎片的帧通过中间服务合并和分离。每一个帧都有关联的属性,同一个消息内有一样的属性类型。有几种类型的帧,文本帧,二进制帧,控制帧等,其它保留的表示帧方式。