对编程而言,Socket是底层网络接口。简而言之,对IPv4, Socket 就是主机(主机名或者IP地址)加上端口号 (host, port),是计算机开发者对传输层协议(TCP/UDP)等的封装实现。
注意: 如果是对IPv6, Socket 就是 (host, port, flowinfo, scope_id)
Python socket API的官方文档参见 socket — Low-level networking interface — Python 3.9.16 documentation,建议感兴趣的读者打开细读。文档开头就提到“The Python interface is a straightforward transliteration of the Unix system call and library interface for sockets to Python’s object-oriented style”, 说明Python 的socket 模块就是根据 C/C++ socket API “直译”,并且按照面向对象风格。
所以以前有过C/C++ socket编程经验的工程师,对Python的socket编程会容易上手。只是需要注意一下 read(), write()被替换成recv(),send()。
1. socket 实例的构造
Python的socket 模块中socket类的构造函数定义如下 (PyCharm 中截图):
AddressFamily 包括:
- socket.AF_UNIX
- socket.AF_INET (用于IPv4)
- socket.AF_INET6 (用于IPv6)
SocketKind 包括:
- socket.SOCK_STREAM (用于TCP,面向连接)
- socket.SOCK_DGRAM (用于UDP,面向无连接)
- socket.SOCK_RAW
- socket.SOCK_RDM
- socket.SOCK_SEQPACKET
2. 流程
2.1 Server 端
- 创建 socket 对象
- 绑定端口 ( bind() )
- 监听端口( listen(N), N是队列大小)
- 等待 Client 端的socket连接 ( conn, new_port = accept() )
- 读取 Client端 数据 ( recv() )
- 发送 Server端 数据 ( send() )
- 关闭 Client端 socket 连接 ( close() )
- 关闭 Server端 socket 连接 ( close() )
2.2 Client 端
- 创建 socket 对象
- 连接Server 端 ( connect() )
- 发送 Client端 数据 ( send() )
- 读取 Server端 数据 ( recv() )
- 关闭 Client端 socket 连接 ( close() )
3. 举例
3.1 Server端 echo 来自 Client端的 数据
# Echo server programimport socketHOST = '' # Symbolic name meaning all available interfacesPORT = 50007 # Arbitrary non-privileged portwith socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) print("received data: ", data.decode("utf-8")) if not data: break conn.sendall(data) conn.close() s.close()
使用 telent localhost 50007 作为Client 端连接上Server, 发送数据,如下图
3.2 Client 端 echo 来自Server 的消息
配合3.1 例子
# Echo client programimport socketHOST = '127.0.0.1' # The remote hostPORT = 50007 # The same port as used by the serverloop = 5with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) for i in range(loop): to_send = "Hello, World. -- " + str(i) s.sendall(to_send.encode("utf-8")) data = s.recv(1024) print('Client Received', repr(data))
执行结果为