ITPub博客

首页 > 数据库 > 数据库开发技术 > WebSocket 是什么原理?为什么可以实现持久连接?

WebSocket 是什么原理?为什么可以实现持久连接?

原创 数据库开发技术 作者:皇子谈技术 时间:2024-08-29 18:17:09 0 删除 编辑

WebSocket 全双工,你可以主动找我,我也可以主动找你。

大家好,我是皇子。

WebSocket 像是个特立独行的技术,不走寻常路,但偏偏又能解决很多实际问题。

WebSocket 是什么原理?

关于WebSocket简单来说,它提供了一种机制,可以让客户端和服务端之间保持一个持久的连接,这样双方就可以实时通信了。

这在以前的 HTTP  世界里几乎是不可能的,因为 HTTP 本质上是一个请求/响应模型,一次请求结束后,连接就会被关闭,下次通信还得重新建立连接。

为什么可以实现持久连接?

WebSocket 实现持久连接的的核心技术点在于它的握手过程:

下面我们将围绕这个图进行分析:

客户端向服务端发起WebSocket连接请求

刚开始的时候,WebSocket 使用一个类似于 HTTP 的握手请求,这个请求看起来像是普通的 HTTP  请求,但它里面包含了特殊的头部信息,告诉服务器这不是普通的 HTTP 请求,而是希望升级到 WebSocket  协议。

1) Upgrade: 这个头告诉服务器,客户端想要升级当前的连接到 WebSocket 协议。值通常是 websocket。

Upgrade: websocket

2) Connection: 这个头用来指定当前连接应该被升级。值通常是 Upgrade。

Connection: Upgrade

3) Sec-WebSocket-Key: 这是一个随机生成的 Base64 编码的字符串,用于握手验证。服务器需要使用这个键来计算一个特殊的响应值,以确认握手成功。

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

4) Sec-WebSocket-Version: 这个头指定了 WebSocket 协议的版本。目前最常用的版本是 13。

Sec-WebSocket-Version: 13

5) Host: 这个头和普通 HTTP 请求一样,表示请求的目标主机。

6) Origin: 这个头指明了发起请求的页面的来源,即发起 WebSocket 连接的网页地址。

Websocket服务端收到客户端请求并响应

服务器收到这个请求后,如果同意的话,就会发送一个特殊的响应,然后双方就切换到 WebSocket  通道进行通信了。

服务器接收到这个请求后,会检查这些头部信息,并作出相应的响应。响应中同样包含了一些关键头部:

1) Upgrade: 同样是 websocket。

Upgrade: websocket

2) Connection: 同样是 Upgrade。

Connection: Upgrade

3) Sec-WebSocket-Accept: 这个头包含了经过特殊计算后的值,用于验证客户端的 Sec-WebSocket-Key。具体算法是将客户端发送的 Sec-WebSocket-Key 字段加上一个固定的字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然后取 SHA-1 哈希,再进行 Base64 编码。

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

握手成功后,连接就升级成了 WebSocket 连接。一旦这个通道打开,双方就可以持续不断地交换数据,直到一方主动断开连接为止。

就是这时候,通信模式就从 HTTP 的请求/响应模式转变成了全双工模式,客户端和服务端可以同时发送数据而不必等待对方回应。


至于为啥 WebSocket 能保持连接不掉线,那是因为它设计了一套心跳机制,每隔一段时间,双方就得发个心跳包,就相当于说:“哥们儿,我还活着呢!”,这样服务器就不会误以为客户端死掉了,就把连接给关了。

这种模式非常适合需要实时交互的应用场景,如在线聊天、股票报价更新、多人游戏等。

WebSocket 跟 HTML5 有关联?

这是因为 HTML5 是一个大升级,它引入了很多新的 API 和特性,WebSocket  就是其中之一。

在 HTML4 时代,确实没有 WebSocket 这个东西,那时候要实现类似的功能,开发者们得费老大劲,用各种 hack  技术来模拟持久连接,比如轮询或者长轮询等。这些方法不仅效率低,而且用户体验也不好。

到了 HTML5 时代,WebSocket  成为了标准的一部分,开发者们可以直接使用浏览器提供的 WebSocket API,这大大简化了开发过程。

websocket和普通的socket有什么区别?

我想起之前没有那么多丰富的开发框架时,网络编程基本靠纯“手动挡”,一手 TCP,一手 HTTP,两眼一抹黑就开干。

对于普通 Socket(通常指 TCP Socket)是网络编程中的一种基础组件,用于在两台计算机之间建立双向通信连接。它是基于 TCP/IP 协议族中的传输控制协议 (TCP) 实现的,为应用程序提供了一个稳定的、面向连接的数据流服务。

而WebSocket 是一种协议,旨在为 Web 应用程序提供高效、双向的通信通道。它构建于 TCP 协议之上,并利用 HTTP 协议进行握手,之后转换为持久连接,以支持实时数据交换。

在对比区别之前,我们通过实现一个双向通信的过程,先了解下大致过程;

WebSocket

  • WebSocket 服务器端伪代码
import asyncio
from websockets import serve

async def handle_websocket(websocket, path):
# 接收客户端消息
async for message in websocket:
print(f"Received: {message}")
# 处理消息逻辑
response = process_message(message)
# 向客户端发送响应
await websocket.send(response)

async def main():
# 在指定端口启动 WebSocket 服务器
async with serve(handle_websocket, "localhost", 8765):
print("WebSocket server is running...")
await asyncio.Future() # 运行服务器

if __name__ == "__main__":
asyncio.run(main())
  • WebSocket 客户端伪代码
import asyncio
import websockets

async def send_and_receive():
uri = "ws://localhost:8765"
async with websockets.connect(uri) as websocket:
while True:
# 发送消息给服务器
message = input("Enter a message: ")
await websocket.send(message)
# 接收并打印服务器响应
response = await websocket.recv()
print(f"Received: {response}")

if __name__ == "__main__":
asyncio.run(send_and_receive())

普通 Socket

  • 普通 Socket 服务器端
import socket
import threading

def handle_client(client_socket, address):
try:
while True:
data = client_socket.recv(1024).decode()
if not data:
break
print(f"Received from {address}: {data}")
response = process_message(data)
client_socket.sendall(response.encode())
finally:
client_socket.close()

def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(5)
print("Server is listening...")

while True:
client_socket, addr = server_socket.accept()
thread = threading.Thread(target=handle_client, args=(client_socket, addr))
thread.start()

if __name__ == "__main__":
start_server()
  • 普通 Socket 客户端
import socket

def connect_to_server():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))

while True:
message = input("Enter a message: ")
client_socket.sendall(message.encode())

data = client_socket.recv(1024).decode()
if not data:
break
print(f"Received: {data}")

client_socket.close()

if __name__ == "__main__":
connect_to_server()

WebSocket 与普通 Socket主要区别

1、连接建立

  • 普通 Socket 直接通过 TCP 连接建立。
  • WebSocket 则通过 HTTP/HTTPS 进行初始的握手过程,之后才转换为持久的双向通信连接。

2、数据格式

  • 普通 Socket 可以传输任意类型的数据,包括文本和二进制数据。
  • WebSocket 默认传输 JSON 或文本数据,但同样支持二进制数据。

3、通信模式

  • 普通 Socket 支持双向通信,但通常需要应用程序自行处理心跳机制来保持连接的活跃状态。
  • WebSocket 自带心跳机制,确保连接的稳定性和双向通信能力。

4、安全性

  • 普通 Socket 可以使用 SSL/TLS 加密以提高安全性。
  • WebSocket 也可以通过 WSS (WebSocket Secure) 提供安全连接,确保数据传输的安全性。

5、应用范围

  • 普通 Socket 广泛应用于各种网络编程场景,包括但不限于文件传输、远程控制等。
  • WebSocket 特别适用于需要实时数据更新的应用场景,如在线聊天、实时游戏、股票行情推送等。

以上,点亮【赞与在看】让我们心中充满力量、披荆斩棘、不惧未来!

【推荐阅读】

快手一面,这拷打我经不住

大学生就业青睐的城市排行出炉,竟然没有这座城市!

美团面试的新方式,涨见识了


关于作者:一位热爱技术,并在职场与自媒体间探索的实践者,希望通过分享个人经验和见解,帮助更多人实现自我成长和价值。

如果您对我的公众号内容感兴趣,欢迎关注我。

也可以在下方添加我微信和一支烟花AI社区技术群,一起交流技术、职场心得。

原文作者:皇子谈技术;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2023-12-21

  • 博文量
    113
  • 访问量
    56512