Socket和Websocket编程的区别
一、区别
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
服务器端
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()
客户端
import socket# 服务器配置
HOST = '127.0.0.1'
PORT = 65432def 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
服务器端
import asyncio
import websockets# 服务器配置
HOST = '127.0.0.1'
PORT = 8765async 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())
客户端
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 地址和端口号唯一标识的通信端点。
