前言
很久没写博客了呢。这次是要用 python 实现一个简单的 TCP 客户端,在主线程中发送信息,然后子线程中接收信息,这样就不会因为 socket 接收信息的阻塞而影响速度了。
环境
- win10 1909
- python 3.7.5
程序实现
不说废话了,直接把程序贴上来吧~
import time
import socket
import threading
socket_flag = False
socket_msg = ""
clientSocket = None
def SocketReceive(clientSocket):
''' Socket 接收线程。'''
global socket_flag, socket_msg # 通过全局变量,让外部可以控制线程的运行,也可以处理信息
while socket_flag:
try:
recvData = clientSocket.recv(64)
except socket.timeout: # 忽视掉超时
continue
if len(recvData) > 0:
socket_msg = recvData.decode() # 将接收到的字节数据转为 string
print("Socket receive: " + socket_msg)
clientSocket.close()
print("Client closed.")
if __name__ == '__main__':
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
address = ('127.0.0.1', 8080)
serverSocket.bind(address) # 绑定地址
serverSocket.listen(2) # 监听最多两个客户端(虽然我只计划连进来一个)
# 连接外部客户端,并设置超时
print("Waiting a client...")
clientSocket, destAddr = serverSocket.accept()
clientSocket.settimeout(5) # 单位:秒
print("Client connected.")
try:
# 启动线程
socket_flag = True
t2 = threading.Thread(target=SocketReceive, args=(clientSocket, ))
t2.start()
# 在主线程中执行发送任务
count = 10
while count:
clientSocket.send(b'3')
count -= 1
time.sleep(1.5)
clientSocket.send(b'---------')
print("Sending complete.")
socket_flag = False
t2.join() # 此处等待子线程完结,并关闭客户端连接
serverSocket.close()
print("Done.")
except Exception as e:
print("Error: ", e)
运行结果
用 socket 调试工具,在回环地址 127.0.0.1 中测试如下:
主线程一直在进行发送直到达到次数,中途也可以接受客户端传来的数据信息,并且程序完成后能够正常退出。
小结
程序蛮简单的,主要是被 socket 的阻塞搞得有点烦,用这种方式就可以正常退出程序了。不过,这个方法只是打算解决服务器先于客户端关闭的情况。如果系统设计中,客户端先退出,则不需要设置 timeout,可以把线程改为如下形式:
def SocketReceive(clientSocket):
''' Socket 接收线程。'''
global socket_flag, socket_msg # 通过全局变量,让外部可以控制线程的运行,也可以处理信息
while socket_flag:
recvData = clientSocket.recv(64)
if len(recvData) > 0:
socket_msg = recvData.decode() # 将接收到的字节数据转为 string
print("Socket receive: " + socket_msg)
else: # 阻塞状态下如果能运行到这里就说明客户端关闭了。
break
clientSocket.close()
print("Client closed.")