合作机构:阿里云 / 腾讯云 / 亚马逊云 / DreamHost / NameSilo / INWX / GODADDY / 百度统计
本次我们来聊一聊 Socket,以及它如何与 asyncio 搭配使用。
Socket 是对 TCP/IP 协议的一个封装,可以让我们更方便地使用 TCP/IP 协议,而不用关注背后的原理。并且我们经常使用的 Web 框架,本质上也是一个 Socket。
所以 Socket 是操作系统对 TCP/IP 网络协议栈的封装,并提供了一系列的接口,我们通过这些接口可以实现网络通信,而不用关注网络协议的具体细节。
图片
按照现有的网络模型,Socket 并不属于其中的任何一层,但我们可以简单地将 Socket 理解为传输层之上的抽象层,负责连接应用层和传输层。Socket 提供了大量的 API,基于这些 API 我们可以非常方便地使用网络协议栈,在不同主机间进行网络通信。
Linux 一切皆文件,Socket 也不例外,它被称为套接字文件,在使用上和普通文件是类似的。
Socket 是什么我们已经知道了,下面来看看如何使用 Socket 进行编程。
图片
整个过程如下:
我们使用来编写代码演示一下这个过程,首先是服务端:
import socket
# socket.socket() 会返回一个「主动套接字」
server = socket.socket(
# 表示使用 IPv4,如果是 socket.AF_INET6
# 则表示使用 IPv6
socket.AF_INET,
# 表示建立 TCP 连接,如果是 socket.SOCK_DGRAM
# 则表示建立 UDP 连接
socket.SOCK_STREAM
)
# 当然这两个参数也可以不传,因为默认就是它
# 设置套接字属性,这里让端口释放后立刻就能再次使用
server.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, True)
# 将「主动套接字」绑定在某个 IP 和端口上
server.bind(("localhost", 12345))
# 监听,此时「主动套接字」会变成「监听套接字」
server.listen(5)
# 调用 accept,等待客户端连接,此时会阻塞在这里
# 如果客户端连接到来,那么会返回「已连接套接字」,也就是这里的 conn
# 至于 addr 则是一个元组,保存了客户端连接的信息(IP 和端口)
conn, addr = server.accept()
# 下面我们通过「已连接套接字」conn 和客户端进行消息的收发
# 收消息使用 recv、发消息使用 send,和 read、write 本质是一样的
while True:
msg = conn.recv(1024)
# 当客户端断开连接时,msg 会收到一个空字节串
if not msg:
print("客户端已经断开连接")
conn.close()
break
print("客户端发来消息:", msg.decode("utf-8"))
# 然后我们加点内容之后,再给客户端发过去
conn.send("服务端收到, 你发的消息是: ".encode("utf-8") + msg)
TOP