Python 处理TCP连接
概要: 使用Python建立TCP服务,或者作为TCP客户端发送数据
创建时间: 2022.12.07 21:38:15
更新时间: 2022.12.07 22:33:05
建立TCP服务端
使用Python建立一个简单的TCP服务,大致分为三步走
- 创建一个
socket
对象作为TCP server,并绑定到指定端口
- 开启监听指定端口的连接,处理来自客户端的请求
- 关闭服务
实例化如下 server.py
Python |
---|
| import socket
tcp_addr = ("0.0.0.0", 12345)
# 开启TCP服务,监听连接到本机 12345 端口的数据
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(tcp_addr)
tcp_server.listen()
print(f"TCP server, listening {tcp_addr}")
# 获取一条来自客户端的请求数据
client_conn, client_addr = tcp_server.accept()
data = client_conn.recv(10240).decode("utf-8")
print(f"Received TCP client data: {data}")
# 关闭TCP服务
tcp_server.close()
print(f"TCP server, has closed.")
|
解释
"0.0.0.0"
表示建立的TCP服务接收来自所有IPV4地址的请求
AF_INET
表示 Address Family 中的IPV4协议,同理 AF_INET6
表示IPV6协议
SOCK_STREAM
表示我们建立的是TCP连接,同理 SOCK_DGRAM
是UDP连接
建立TCP客户端
如果需要使用Python通过TCP协议发送数据,与上面类似,也分为三步
- 创建一个
socket
对象作为TCP client,并连接到指定的TCP服务器(服务器IP和端口)
- 向TCP服务器请求发送或接收数据
- 关闭连接
实例化如下 client.py
Python |
---|
| import socket
# 连接到本机的12345端口
tcp_addr = ("127.0.0.1", 12345)
# 建立与服务端的TCP连接
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect(tcp_addr)
# 注意发送的数据必须是字节流,一般使用UTF-8格式
tcp_client.sendall("hello world".encode("utf-8"))
# 关闭与服务端的TCP连接
tcp_client.close()
|
同时处理多个客户端请求
如果需要TCP服务端同时处理多个客户端的请求,可以采取多线程的方式,对于一段时间不活动的客户端连接,可以主动关闭连接节省系统资源,代码实现如下
Python |
---|
| import signal
import socket
import threading
import time
import typing
def handle_sigterm(*args):
"""接收中断信号,安全关闭tcp连接"""
raise KeyboardInterrupt()
class TcpServer(object):
def __init__(self, host: str = "0.0.0.0", port: int = 12345, timeout: int = 60):
self.host = host
self.port = port
self.timeout = timeout
self._addr = (host, port)
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connections = dict()
def start(self):
try:
signal.signal(signal.SIGTERM, handle_sigterm)
self._start()
except KeyboardInterrupt:
self.server.close()
print(f"TCP server closed, bye.")
def _start(self):
self.server.bind(self._addr)
self.server.listen()
print(f"TCP server started, listening on {self._addr}")
while True:
client_conn, client_addr = self.server.accept()
print(f"New TCP client connected, address: {client_addr}")
client_thread = threading.Thread(
target=self._handle_new_client, args=(client_conn, client_addr)
)
client_thread.start()
self.connections[client_addr] = client_thread
def _handle_new_client(
self, client_socket: socket.socket, client_addr: typing.Tuple[str, int]
):
last_communication = time.time()
while time.time() - last_communication < self.timeout:
if data := client_socket.recv(10240).decode("utf-8"):
print(f"New data from client {client_addr}: {data}")
last_communication = time.time()
else:
time.sleep(1)
client_socket.close()
print(f"TCP client {client_addr} closed due to timeout")
self.connections.pop(client_addr)
if __name__ == "__main__":
tcp_server = TcpServer()
tcp_server.start()
|
参考