一、区别
WebSocket 和 Socket 之间的最大区别是它们是如何在应用程序和服务器之间传输数据的。
(1)socket
Socket 是一个应用程序和底层操作系统之间的接口,它允许应用程序通过TCP 和 UDP 协议来发送和接收数据。Socket 主要用于客户端和服务器之间的数据传输。Socket 需要建立连接之后,才能进行数据传输。
通常情况下,应用程序通过使用套接字接口发送 TCP 协议的数据来实现 Socket。
(2)websocket
WebSocket 是一种网络协议,建立在 HTTP 协议之上,允许双向通信。WebSocket 协议允许服务器发送数据到客户端,同时也可以让客户端向服务器发送数据。WebSocket 使用 HTTP 协议的升级请求和响应来建立连接。WebSocket 的主要优点在于它可以通过单一的TCP连接来实现双向通信,从而减少了连接的开销并提高了数据传输的速度。
在总体上,WebSocket 相对于 Socket 来说,是一种更高级的技术。
Socket 处理低层次的网络传输,而 WebSocket 是在 HTTP 协议之上的二层协议,使用更容易,效率也更高,同时也支持双向实时通讯。

总体而言,socket和websocket的主要区别如下:
- 协议不同:Socket是基于传输层TCP协议实现的,而Websocket是基于HTTP协议的;Socket通信是通过Socket套接字来实现的,而Websocket通信是通过HTTP的握手过程实现的。
- 持久化连接:传统的socket通信是基于短连接的,通信完成后即断开连接;而websocket是基于长连接的,即建立连接后可以长久通信,避免了客户端和服务端频繁连接和断开的过程。
- 双向通信:传统的socket通信只支持单向通信,服务器只有接受到客户端的请求以后才能给予响应;websocket可以实现双向通信,即服务器和客户端之间可以相互请求和响应,实时通信效果更佳。
- 效率:socket通信具有高效性和实时性,因为传输数据的时候没有HTTP协议的请求头信息;websocket除了HTTP协议的请求头之外,还需要发送额外的数据,因此通信效率相对较低。
三、代码实现
(1)socket
服务器端
python
import socket
import threading
# 服务器配置
HOST = '127.0.0.1' # 本地主机
PORT = 65432 # 端口号
def handle_client(conn, addr):
"""处理客户端连接的线程函数"""
print(f"新连接: {addr}")
try:
while True:
# 接收数据,一次最多 1024 字节
data = conn.recv(1024)
if not data:
break # 客户端关闭连接
message = data.decode('utf-8')
print(f"收到来自 {addr} 的消息: {message}")
# 回复客户端,将消息转为大写
response = f"Server received: {message.upper()}"
conn.sendall(response.encode('utf-8'))
except ConnectionResetError:
print(f"客户端 {addr} 意外断开")
finally:
# 关闭连接
print(f"连接关闭: {addr}")
conn.close()
def start_socket_server():
"""启动 Socket 服务器"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# 允许重用地址,避免"Address already in use"错误
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen()
print(f"Socket 服务器启动在 {HOST}:{PORT}, 等待连接...")
while True:
# 接受新连接
conn, addr = s.accept()
# 为每个新连接创建一个新线程处理
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print(f"活动连接数: {threading.active_count() - 1}")
if __name__ == '__main__':
start_socket_server()
客户端
python
import socket
# 服务器配置
HOST = '127.0.0.1'
PORT = 65432
def start_socket_client():
"""启动 Socket 客户端"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
print(f"尝试连接到 {HOST}:{PORT}...")
s.connect((HOST, PORT))
print("连接成功!")
messages = ["hello world", "python socket", "real-time data"]
for msg in messages:
print(f"\n发送: {msg}")
s.sendall(msg.encode('utf-8'))
# 接收服务器的响应
data = s.recv(1024)
print(f"收到响应: {data.decode('utf-8')}")
except ConnectionRefusedError:
print(f"连接失败: 无法连接到 {HOST}:{PORT}。请确保服务器已运行。")
finally:
print("客户端连接关闭。")
if __name__ == '__main__':
start_socket_client()
(2)websocket
服务器端
python
import asyncio
import websockets
# 服务器配置
HOST = '127.0.0.1'
PORT = 8765
async def echo(websocket):
"""处理 WebSocket 连接和消息"""
print(f"新 WebSocket 连接: {websocket.remote_address}")
try:
async for message in websocket:
print(f"收到消息: {message}")
# 将收到的消息转为大写并发送回客户端
response = f"Server echoed: {message.upper()}"
await websocket.send(response)
except websockets.exceptions.ConnectionClosedOK:
print(f"WebSocket 连接正常关闭: {websocket.remote_address}")
except websockets.exceptions.ConnectionClosedError as e:
print(f"WebSocket 连接意外断开 ({e.code}): {websocket.remote_address}")
finally:
print(f"连接处理结束: {websocket.remote_address}")
async def start_websocket_server():
"""启动 WebSocket 服务器"""
async with websockets.serve(echo, HOST, PORT):
print(f"WebSocket 服务器启动在 ws://{HOST}:{PORT}, 等待连接...")
await asyncio.Future() # 永久运行
if __name__ == "__main__":
asyncio.run(start_websocket_server())
客户端
python
import asyncio
import websockets
# 服务器配置
URI = "ws://127.0.0.1:8765"
async def start_websocket_client():
"""启动 WebSocket 客户端"""
try:
async with websockets.connect(URI) as websocket:
print(f"连接到 {URI} 成功!")
messages = ["Async Python", "WebSocket Protocol", "Ping Pong Test"]
for msg in messages:
# 客户端发送消息
await websocket.send(msg)
print(f"\n发送: {msg}")
# 客户端接收响应
response = await websocket.recv()
print(f"收到响应: {response}")
except ConnectionRefusedError:
print(f"连接失败: 无法连接到 {URI}。请确保 WebSocket 服务器已运行。")
except websockets.exceptions.InvalidURI:
print("错误: URI 格式不正确。")
except Exception as e:
print(f"发生其他错误: {e}")
finally:
print("\n客户端运行结束。")
if __name__ == "__main__":
asyncio.run(start_websocket_client())
补充套接字的含义
"套接字"(Socket)在计算机网络编程中是一个非常核心的概念,尤其是在使用 socket 库进行网络通信时。
简单来说,套接字是应用程序与网络协议栈(TCP/IP 协议族)进行通信的接口或端点。 它是实现网络通信的一种抽象机制。
1. 编程接口 (API)
在编程层面,套接字是你调用网络功能的 API。
- 当你用 Python 的
socket.socket()创建一个对象时,你就创建了一个套接字。 - 这个对象提供了一系列方法(如
bind、listen、connect、send、recv),允许你的应用程序执行网络操作。
打个比方: 套接字就像你家墙上的一个电话插孔。
- 你想打电话(发送/接收数据),你不需要知道电话线是怎么铺的,也不需要知道电信局的内部结构。
- 你只需要把电话(你的应用程序)插到这个插孔(套接字)上,然后拨号(
connect)或等待来电(listen)。
2. 通信端点(Endpoint)
在网络通信层面,一个套接字代表一个唯一的通信端点。
对于互联网上的通信,一个完整的通信端点(即一个唯一的套接字标识)通常由以下 五元组 构成:
协议 + 源 IP 地址 + 源端口号 + 目标 IP 地址 + 目标端口号 \text{协议} + \text{源 IP 地址} + \text{源端口号} + \text{目标 IP 地址} + \text{目标端口号} 协议+源 IP 地址+源端口号+目标 IP 地址+目标端口号
- IP 地址:标识了网络上的哪台主机。
- 端口号:标识了主机上运行的哪个应用程序(进程)。
例如: 当你在浏览器中访问一个网页时:
- 你的浏览器会创建一个套接字。
- 这个套接字标识为:TCP + 你的电脑IP + 随机端口 + 服务器IP + 80/443端口。
3. 系统资源(操作系统内核)
在操作系统内核层面,套接字是一个由操作系统维护的数据结构,用于记录和管理一次网络连接或通信的所有必要信息,包括:
- 连接状态(例如:已连接、正在监听)。
- 发送和接收数据的缓冲区。
- 使用的协议(TCP、UDP 等)。
- 本地和远程的地址/端口信息。
套接字总结
| 角色 | 套接字 (Socket) 的含义 |
|---|---|
| 对于程序员 | 调用网络功能的 API 对象。 |
| 对于网络通信 | 一次通信的唯一端点标识(IP + 端口)。 |
| 对于操作系统 | 维护网络连接状态和数据的内核资源。 |
因此,当你说"socket 里面的套接字"时,通常指的就是那个用来进行网络数据交换、由 IP 地址和端口号唯一标识的通信端点。