一、Socket
Socket是什么
当我们打开一个网页,比如www.baidu.com,展示百度的首页。
浏览器是怎么获取到的百度首页的内容展示给用户的?是浏览器跟百度的服务器进行通信,服务器处理用户的请求后,把数据传回来展示给用户。本质上是发起https请求,浏览器是怎么找到服务器的?怎么发送、接收消息?
- 操作系统提供了统一的通信机制:
Socket(套接字)。它是用于不同主机之间通信的API,在操作系统的层面上。
Socket和操作系统说:帮我连接对方,帮我发送、接收消息。当我们使用socket进行通信的时候,需要知道IP地址加端口号,IP地址用于唯一标识网络设备,操作系统区不知道把数据发到哪个应用上,端口是区分主机上不同应用的。
通过Socket可以建立一条不同主机,不同应用之间的虚拟数据通道,并且它是点对点(应用对应用的),一个形象的比喻是一条将数据线连接在不同应用的插槽上。它是最底层的工具,数据怎么传,它并不管,只负责连通。
Socket出现之前的问题
我们知道,Socket是操作系统提供的统一的用于网络通信的抽象接口(API)。不同电脑之间通过网络进行接收、发送消息都需要调用Socket。
如果没有Socket,会有什么样的问题?
- 1、打开www.baidu.com时,首先需要连接百度的服务器。如果没有Socket,浏览器并不知道怎么连接。
- 2、当我们写程序时,需要处理怎么跟另一台电脑通信的问题。此时我们不仅仅需要编写代码,还需要处理网络方面的问题:如何把数据发送给另一台电脑?如何发送、接收数据包?
- 3、没有统一的Socket接口,Windows、Linux、MacOS各个操作系统都有一套自己的Socket方法,跨平台开发会变得非常困难。
Socket解决了上述问题:
- 1、Socket通过
IP+端口号跟其他电脑进行通信。 - 2、Socket提供了统一的编程接口,开发者只需要调用connect、send、recv、bind、listen等方法,就可以完成数据的发送与接收,无需自己处理底层网络细节。
- 3、程序员通过统一的 Socket API 进行网络开发,不同操作系统之间的底层实现差异由操作系统屏蔽,开发者无需关心具体细节。
没有 Socket 这种统一抽象接口,应用层网络开发会极其困难。
二、代码模拟客户端和服务端
服务端
server.py
import socket
# 创建 socket 对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定IP和端口
server.bind(("127.0.0.1", 8888))
# 开始监听(最多3个等待连接的排队队列)
server.listen(3)
print("服务端启动,等待客户端连接...")
# 等待客户端连接
conn, addr = server.accept()
print("客户端已连接:", addr)
while True:
# 从客户端接收数据,最多1024字节。如果消息超过1024,需要多次recv拼起来
data = conn.recv(1024)
if not data:
break
msg = data.decode("utf-8")
print("收到客户端消息:", msg)
reply = f"服务端收到:{msg}"
conn.send(reply.encode("utf-8"))
# 关闭连接
conn.close()
server.close()客户端
client.py
import socket
# 创建 socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务端
client.connect(("127.0.0.1", 8888))
while True:
msg = input("请输入消息:")
if msg == "exit":
break
client.send(msg.encode("utf-8"))
data = client.recv(1024)
print("服务端回复:", data.decode("utf-8"))
client.close()运行步骤
- 先启动服务端:
python 3 server.py - 输出:
服务端启动,等待客户端连接... - 启动客户端:
python 3 client.py - 输入:
hello - 客户端显示:
- 服务端显示:
三、WebSocket
WebSocket是什么,解决了什么问题
WebSocket 是应用层协议,运行在TCP(Socket)连接之上,让浏览器和服务器之间建立一条持续连接的双向通道,双方随时可以主动发消息。
我们在网页中点击某个商品时,浏览器主动向服务器发出请求。这种情况下,服务器从来不会主动给客户端发消息。
当我们在网页端打游戏的时候,游戏中的小怪源源不断地输出伤害,角色血量变少。这个时候是怎么做到在用户不做任何操作的情况下,网页能够收到消息进行变更呢?
解决方法有很多,比如HTTP定时轮询,网页的前端代码里会不断定时发送HTTP请求到服务器,服务器收到后响应消息。最常见的应用是扫码登录。
它有两个缺点:
- 1、服务器没有更新数据,客户端持续请求,浪费了很多资源
- 2、如果用户很多,那么即使是只查状态接口,也会给服务器带来很大的压力。
- 3、实时性差,轮询并不是实时推送,而是下次询问才知道。用户会觉得卡顿,有延迟感。
还有一种解决方法是长轮询。HTTP发出请求后,服务器会留出一定的时间做响应,比如3秒,如果规定时间内没响应就是超时。那我们将这个超时时间延长,比如30秒,如果超时,就再进行下一次请求。这样HTTP请求的次数减少了,并且大部分情况下用户都会在30秒内完成登录,用户体验感增强。
以上两种解决方法本质上都是客户端主动进行请求,而不是服务器主动给客户端发消息。扫码登录还可以使用,但是网页游戏就不行了,因为游戏中客户端和服务端都有大量的数据需要互相推送。
HTTP/1.1、HTTP/2、WebSocket都是基于TCP协议的。TCP协议是全双工的,全双工就是双方可以同时接收、发送数据,就像寄信。半双工双方都能发送,但是同时只有一方可以发送数据,就像打电话。
HTTP可以理解为是半双工的,通信必须由客户端发起,服务器被动响应。但是我们需要一个可以同时接收、发送数据的,这个时候就有了一个新的协议:WebSocket,它是基于TCP的全双工应用层协议。
建立WebSocket连接
建立过程:
- 1、用户端和服务器建立建立连接后,先使用HTTP进行一次通信,在HTTP请求头中带上特殊的header头。这一步叫
HTTP Upgrade握手。
关键字段:
Connect: Upgrade // 告诉服务器想把当前 HTTP 连接升级成 WebSocket
Upgrade: websocket // 表示此次连接用于升级协议
- 2、服务器到后,如果支持 WebSocket,就返回:
HTTP/1.1 101 Switching Protocols // 101:同意切换协议
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: xxxxx
- 3、进入长连接通信。双方发送的不是HTTP文本,而是WebSocketFrame(数据帧),可以主动发消息。
底层
实际上底层TCP连接只建立了一次,WebSocket并没有重新建立连接,只是更换了上层协议。
WebSocket和Socket有什么关系呢
我们知道, 不仅仅有Socket,还有WebSocket。那WebSocket和Socket有什么关系呢?
Socket(底层能力):就像“修路”。不管是运人还是运货,首先要有条路(TCP连接)。而Socket是负责把这条路修通的工具。
WebSocket(上层规则):就像是路上跑的“高铁”。它是在这条路(Socket/TCP)修好之后,专门制定的一套交通规则(协议)。
Socket是通用的,什么数据都能传。WebSocket是专用的,专门给浏览器用的,为了让网页能够实时收到消息。
四、总结
概念总结
如果用一句话总结:
- Socket 是操作系统提供的“网络通信能力接口”
- WebSocket 是建立在 TCP + Socket 之上的“实时双向通信协议”
Socket 解决的是“怎么连通两台机器”的问题,它更偏底层,是所有网络通信的基础能力;而 WebSocket 解决的是“在网页中如何高效地实时通信”的问题,它更偏应用层,是对 HTTP 交互模式的一种补充。
可以这样理解它们的关系:
Socket 是“底层通道”,WebSocket 是“在通道上制定的一种通信规则”。
“WebSocket和Socket,其实跟雷锋和雷峰塔一样,二者接近毫无关系。”
适用场景总结
- HTTP 请求(短连接):页面加载、商品查询、表单提交
- 轮询 / 长轮询:扫码登录状态、简单消息刷新
- WebSocket(长连接 + 双向实时通信):在线游戏、股票行情、弹幕、实时协作(在线文档)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。