传统的 HTTP 请求通常是一次请求一次响应的,而 WebSocket 则可以建立一个持久连接,允许服务器即时向客户端推送数据,同时也可以接收客户端发送的数据。WebSocket 相比于传统的轮询或长轮询方式,能够显著减少网络流量和延迟,提高数据传输的效率和速度。它对实时 Web 应用程序和在线游戏的开发非常有用;
websocket 基础原理
WebSocket 是 HTML5 开始推出的基于 TCP 协议的双向通信协议,其优势在于与 HTTP 协议兼容、开销小、通信高效。WebSocket 让客户端和服务器之间建立连接,并通过这个持久连接实时地进行双向数据传
WebSocket 最主要的特点就是建立了一个可持久化的 TCP 连接,这个连接会一直保留,直到客户端或者服务器发起中断请求为止。WebSocket 通过 HTTP/1.1 协议中的 Upgrade 头信息来告诉服务器,希望协议从 HTTP/1.1 升级到 WebSocket 协议
WebSocket 建立在 HTTP 协议之上,所有的 WebSocket 请求都会通过普通的 HTTP 协议发送出去,然后在服务器端根据 HTTP 协议识别特定的头信息 Upgrade,服务端也会判断请求信息中 Upgrade 是否存在。 这里面 HTTP 是必不可少的,不然 WebSocket 根本无法建立。特别的,WebSocket 在握手时采用了 Sec-WebSocket-Key 加密处理,并采用 SHA-1 签名。
一旦建立了 WebSocket 连接,客户端和服务器端就可以互相发送二进制流或 Unicode 字符串。所有的数据都是经过 mask 处理过的,mask 的值是由服务器端随机生成的。在数据进行发送之前,必须先进行 mask 处理,这样可以有效防止数据被第三方恶意篡改。
WebSocket 与 Socket、TCP、HTTP 的关系及区别
power by openai
WebSocket、Socket、TCP 和 HTTP 都涉及到计算机网络中的数据传输,但它们的协议、用途、工作方式等方面有显著的差异。下面是它们之间的关系和主要区别:
1. WebSocket
定义:WebSocket 是一种基于 TCP 协议的全双工通信协议,它使得客户端和服务器之间可以建立一个持久的、双向的通信通道。WebSocket 允许客户端和服务器在同一个连接上进行实时数据交换,适合用于需要频繁交互的应用(如聊天应用、在线游戏等)。
工作方式:WebSocket 在初始连接时通过 HTTP 协议进行握手,但之后会升级为 WebSocket 协议,建立一个持久的 TCP 连接。这意味着一旦连接建立,数据可以在客户端和服务器之间双向流动,而无需每次请求都重新建立连接。
优点:
双向通信:客户端和服务器都可以主动发送数据。
低延迟:避免了 HTTP 请求-响应的开销,减少了频繁建立连接的成本。
实时性:适合实时应用,如股票行情、在线游戏、聊天系统等。
使用场景:实时通信、在线游戏、在线协作、即时通知等。
2. Socket
定义:Socket 是一种提供数据传输的接口,是程序与网络之间通信的基础。它是操作系统层面的抽象,能够让应用程序进行网络通信。Socket 可以支持多种协议(如 TCP、UDP 等),并提供了一种抽象接口,让开发者无需关注底层的网络协议。
工作方式:Socket 本身并不是一个协议,而是一个通信接口。它允许应用程序通过 IP 地址和端口进行数据发送和接收。Socket 本身可以基于不同的协议实现,如 TCP 或 UDP。
与 WebSocket 的关系:WebSocket 也是通过 Socket 来实现通信的。WebSocket 连接实际上是通过 TCP Socket 建立的,它使用 TCP 作为传输层协议,且通过特定的握手协议与 HTTP 进行兼容。
使用场景:一般的客户端-服务器通信,TCP/UDP 应用开发等。
3. TCP (Transmission Control Protocol)
定义:TCP 是一种面向连接的、可靠的传输协议。它在数据传输之前需要通过三次握手建立连接,并且在传输过程中提供错误检测、流量控制、数据重传等机制,确保数据正确、可靠地到达目标。
工作方式:TCP 通过端口号来识别通信的应用进程,并通过 IP 地址和端口号来建立连接。它确保数据包的顺序和完整性,通过确认应答、重传等机制实现可靠性。
与 WebSocket 的关系:WebSocket 使用 TCP 作为底层传输协议。WebSocket 连接在建立时,实际上就是通过 TCP 来进行数据传输的,因此 WebSocket 能够利用 TCP 提供的可靠性和连接保持特性。
使用场景:需要可靠数据传输的场合,如文件传输、HTTP 请求、数据库通信等。
4. HTTP (HyperText Transfer Protocol)
定义:HTTP 是一种无状态、请求-响应式的应用层协议。客户端(如浏览器)向服务器发送请求,服务器响应数据。HTTP 是 Web 应用最常用的协议,用于浏览器和 Web 服务器之间的通信。
工作方式:HTTP 是基于 TCP 协议的,客户端和服务器之间通过 HTTP 请求-响应模式交换数据。每次客户端发送请求时,都会重新建立一个连接(除非使用 HTTP/2 的连接复用功能)。这种请求-响应模式适合静态内容和不频繁交互的场合。
与 WebSocket 的关系:WebSocket 在初始连接时使用 HTTP 协议进行握手。在握手成功后,HTTP 连接会“升级”到 WebSocket 协议,从而切换到基于 TCP 的全双工通信。HTTP 和 WebSocket 都使用 TCP 作为底层协议,但 WebSocket 在通信过程中不再遵循 HTTP 的请求-响应模型。
使用场景:Web 浏览、API 调用、文件下载、网页加载等。
关系与区别总结
简要总结:
WebSocket 适合需要双向实时通信的应用,如在线聊天、实时游戏等。它是建立在 TCP 之上的,初始连接使用 HTTP 协议进行握手。
Socket 是用于网络通信的接口,可以基于 TCP 或 UDP 协议实现。
TCP 是传输层协议,提供可靠的数据传输,WebSocket 在底层依赖 TCP。
HTTP 是请求-响应模型的协议,适用于静态页面加载、API 请求等,但不适合实时通信。WebSocket 在初次连接时使用 HTTP 握手。
代码
JavaScript
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
这个代码创建了一个 WebSocket 客户端,连接到 wss://echo.websocket.org。
在连接建立后,它会发送 "Hello WebSockets!" 到服务器。
服务器会返回相同的消息(因为是回声服务器)。
客户端收到消息后,会打印消息并关闭 WebSocket 连接。
python
The default implementation builds upon
asyncio
, Python’s built-in asynchronous I/O library. It provides an elegant coroutine-based API. It’s ideal for servers that handle many client connections.The
threading
implementation is a good alternative for clients, especially if you aren’t familiar withasyncio
. It may also be used for servers that handle few client connections.The Sans-I/O implementation is designed for integrating in third-party libraries, typically application servers, in addition being used internally by websockets.
asyncio
#!/usr/bin/env python
"""Echo server using the asyncio API."""
import asyncio
import datetime
from websockets.asyncio.server import serve
async def echo(websocket):
"""
async for message in websocket:异步接收 WebSocket 客户端发送的每一条消息。WebSocket 连接是双向的,这里我们接收客户端发来的消息,并通过 message 变量处理。
await websocket.send(message):接收到消息后,立即将该消息发送回客户端。这意味着服务器是一个“回显”服务器,客户端发送什么消息,服务器就回复相同的消息。
"""
async for message in websocket:
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 创建带有时间的消息
message_with_time = f"{current_time} - {message}"
await websocket.send(message_with_time)
async def main():
async with serve(echo, "localhost", 8765) as server:
print("Serving on", server.sockets[0].getsockname())
await server.serve_forever()
if __name__ == "__main__":
print("Serving on port 8765")
asyncio.run(main())
#!/usr/bin/env python
"""Client using the asyncio API."""
import asyncio
from websockets.asyncio.client import connect
async def hello():
async with connect("ws://localhost:8765") as websocket:
await websocket.send("Hello world!")
message = await websocket.recv()
print(message)
if __name__ == "__main__":
asyncio.run(hello())
threading
#!/usr/bin/env python
"""Echo server using the threading API."""
import datetime
import time
from websockets.sync.server import serve
def echo(websocket):
for message in websocket:
time.sleep(10)
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 创建带有时间的消息
message_with_time = f"{current_time} - {message}"
websocket.send(message_with_time)
def main():
with serve(echo, "localhost", 8765) as server:
server.serve_forever()
if __name__ == "__main__":
main()
# client.py
from websockets.sync.client import connect
import threading
import time
def hello(client_id):
print(f"Client {client_id} starting at {time.strftime('%H:%M:%S')}")
with connect("ws://localhost:8765") as websocket:
websocket.send(f"Hello from client {client_id}!")
message = websocket.recv()
print(f"Client {client_id} received at {time.strftime('%H:%M:%S')}: {message}")
def run_clients():
threads = []
for i in range(3): # Testing with 3 clients
thread = threading.Thread(target=hello, args=(i,))
threads.append(thread)
thread.start()
time.sleep(1) # Start clients with slight delay
for thread in threads:
thread.join()
if __name__ == "__main__":
run_clients()
# client_no_threading.py
from websockets.sync.client import connect
import time
def hello(client_id):
print(f"Client {client_id} starting at {time.strftime('%H:%M:%S')}")
with connect("ws://localhost:8765") as websocket:
websocket.send(f"Hello from client {client_id}!")
message = websocket.recv()
print(f"Client {client_id} received at {time.strftime('%H:%M:%S')}: {message}")
def run_clients():
# Sequential execution without threading
for i in range(3):
hello(i)
if __name__ == "__main__":
run_clients()
独立连接:当两个客户端几乎同时发起连接请求时,服务器会为每个客户端创建一个新的WebSocket连接。这意味着每个客户端都有自己的通信通道,服务器可以独立地与每个客户端进行交互。
同步处理 vs 并发连接:尽管服务器对每个连接的消息处理是同步且顺序进行的(即在处理完当前连接的消息之前不会开始处理下一个连接的消息),但这并不妨碍它接受新的连接。因此,如果两个客户端几乎同时发送消息,服务器实际上是在两个不同的连接上工作,而不是试图在一个连接上同时处理两条消息
评论区