从ChatGPT聊天服务上深挖Http、WebScoket和SSE推送技术的区别

简述 —— 三种方式进行通讯

回忆TCP/IP协议

其中,三次握手过程的步骤为:

  1. 客户端向服务端发送 SYN 报文,其中 seq 表示客户端的初始序列号。
  2. 服务端收到 SYN 报文后,向客户端发送 SYN+ACK 报文,其中 ack 表示服务端收到了客户端的序列号,seq 表示服务端的初始序列号。
  3. 客户端收到 SYN+ACK 报文后,向服务端发送 ACK 报文,其中 ack 表示客户端收到了服务端的序列号,seq 表示客户端的下一个序列号。

四次挥手过程的步骤为:

  1. 客户端向服务端发送 FIN 报文,其中 seq 表示客户端最后一次发送数据的序列号。
  2. 服务端收到 FIN 报文后,向客户端发送 ACK 报文,其中 ack 表示服务端收到了客户端的序列号。
  3. 服务端完成数据传输后,向客户端发送 FIN 报文,其中 seq 表示服务端最后一次发送数据的序列号,ack 表示服务端收到了客户端的序列号。
  4. 客户端收到 FIN 报文后,向服务端发送 ACK 报文,其中 ack 表示客户端收到了服务端的序列号。

从ChatGPT项目中引发的思考

项目地址:Grt1228/chatgpt-steam-output: Open AI ChatGPT流式输出。Open AI Stream output. ChatGPT Stream output.GPT-3.5 (github.com)

有感兴趣的朋友可以去拉取下来跑一跑,但是需要过河,这里就不做过多的教程,百度就有:dog2:

下面我直接发测试图

基于SSE

image-20230505115552583
image-20230505115630534
image-20230505115810329

可以看出,SSE是每次客户端都会创建链接,然后服务端返回请求。

但是这个项目又是如何保存会话的?

挖掘源码发现,是在JVM内存中保存了Message上下文

image-20230505120131876
image-20230505120925545

sdk内部采用okHttp进行事件和远程调用的绑定,也就是说每次有请求响应的时候拼装返回前端

image-20230505121842848
image-20230505122005437
image-20230505122151787

基于WebSocket

image-20230505125742757

我们可以看到,这两次会话都是在一次请求里面的

分析

HTTP协议

HTTP/1.0 和 HTTP/1.1 是 HTTP 协议的两个版本,它们之间存在以下几点区别:默认是否开启长连接:HTTP/1.0 默认不支持长连接,需要在请求头中显式地设置 Connection: Keep-Alive 来启用,而 HTTP/1.1 默认支持长连接,无需额外设置。请求方式是否有区别:HTTP/1.1 引入了新的请求方式(如 PUT、DELETE、OPTIONS、TRACE、CONNECT 等),以及增加了对请求方式的扩展性。缓存机制是否有变化:HTTP/1.1 引入了缓存控制机制,可以通过设置 Cache-Control、ETag、If-None-Match 等头部信息来控制缓存的行为,从而提高网站性能。分块传输编码是否有支持:HTTP/1.1 引入了分块传输编码(chunked transfer encoding),可以更高效地传输大型数据。Host 头部是否必须:HTTP/1.0 中没有 Host 头部,而在 HTTP/1.1 中,所有的请求头都必须包含 Host 头部,以便服务器能够处理多个域名和虚拟主机的请求。综上所述,HTTP/1.1 是 HTTP/1.0 的升级版本,引入了许多新特性和改进,提高了网络性能和可扩展性。HTTP/2 是支持多路复用(Multiplexing)的协议,这意味着可以同时发送多个请求,而不需要等待前一个请求的响应。因此,HTTP/2 不是完全的异步操作,而是支持同时处理多个请求和响应的协议。使用 HTTP/2 可以显著提高网站性能和加载速度,因为可以更有效地利用网络资源。

WebSocket协议

img

HTTP长连接是指在一个TCP连接上可以发送多个HTTP请求,而不是每个HTTP请求都需要新建一个TCP连接。HTTP1.1使用了HTTP长连接的机制,可以在一个TCP连接上发送多个HTTP请求和响应,从而避免了重复建立和断开TCP连接的开销。而WebSocket协议是在一个已建立的TCP连接上实现全双工通信,不需要重复建立TCP连接。

SSE推送送技术

SSE(Server-Sent Events)也是一种基于HTTP协议的服务器推送技术,用于实现服务器向客户端推送数据的功能。与WebSocket不同的是,SSE采用的是“单向通信”的方式,即只有服务器向客户端推送数据,客户端不能像WebSocket一样主动向服务器发送数据。

SSE的通信过程也是基于HTTP协议进行的,客户端通过发送一个HTTP请求与服务器建立连接,服务器保持连接处于打开状态,随时可以向客户端推送数据。与WebSocket类似,SSE也可以支持长连接,避免了频繁地建立和关闭连接的开销。但与WebSocket不同的是,SSE的通信过程中,服务器只能向客户端推送文本类型的数据,而不能推送二进制数据。

下面是SSE的通信过程示意图:

其中,Client发送SSE Request建立连接请求,Server返回HTTP Response并设置Content-Type为text/event-stream,表示服务器将向客户端推送SSE数据。服务器可以在任意时刻向客户端发送一条SSE消息,格式为event: <event name>\ndata: <data>\n\n,其中event表示事件名称,data表示要推送的数据。注意,每条消息以两个换行符结尾。

需要注意的是,与WebSocket不同,SSE的通信是基于HTTP协议的,每次请求-响应的过程中都会经过三次握手和四次挥手的过程。因此,SSE并不是真正意义上的实时通信,而是通过保持长连接的方式,实现了一种近似于实时的服务器推送机制。