一个TCP的小程序,把Client做成了一个类,实现了Client、Server,发送、接收接口(可发送和接收多行数据),自动重连,心跳检测,python多线程实现同时执行两个while循环,主要是对网上方法的整合和改进。此程序基于Python 3.7。
Client:
- 发送接口的实现,net_is_ok用来判断当前是否与Server连接,只有连接状态才能发送数据:
- 接收接口的实现,通过引入尾标识End来实现接收多行数据(这些数据以End结尾),这里引用了https://www.cnblogs.com/litaozijin/p/6624029.html 的方法,recv方法本身可以保持长连接(具体请看文档),所以一旦Server关闭导致连接中断,会触发socket.error,然后在except里面调用连接方法,实现自动重连
- 自动重连的实现,因为不知道怎么退出while True方法,就用了一个flag来表示网络连接与否,算是一个笨方法了。
- python多线程实现同时执行两个while循环,困扰了我好久,看这里照着写的https://www.cnblogs.com/zoro-robin/p/6117135.html,注意多线程调用的两个方法后面要加上time.sleep(1)来让另一个线程有运行的机会
- 心跳检测,说明在下面都有注释了,这里Client和Server里面用的是两种不一样的,作用差不多,只是一个可修改参数,一个不可以,感觉对这个心跳检测的应用还是不很理解,都有recv()来判断连接状态了,还需要心跳检测吗?
话不多说,代码如下:
#!/usr/bin/python3
# 文件名:client.py
# 导入 socket模块
import socket
import time
import threading
class Client:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
net_is_ok = True
# 初始化
def __init__(self, host, port):
self.host = host
self.port = port
self.s = self.do_connect(self.host, self.port)
# 心跳检测,1表示启动,后面两个分别表示检测开始时间和间隔,单位为毫秒
self.s.ioctl(socket.SIO_KEEPALIVE_VALS, (1, 10000, 3000))
# 自动重连
def do_connect(self, host, port):
self.net_is_ok = False
# 创建 socket 对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while not self.net_is_ok:
try:
# 连接服务,指定主机和端口
sock.connect((host, port))
self.net_is_ok = True
except socket.error:
print('\n网络错误,开始重连')
time.sleep(3)
return sock
# 发送接口
def send_msg(self):
while True:
if self.net_is_ok:
print("\n请输入你想发送的数据,回车结束:")
# hello = 'Hello' + "\r\n"
hello = input('>>')
hello = hello + "\r\n"
self.s.send(hello.encode())
time.sleep(1)
# 接收接口
def receiver_msg(self):
End = r'\r\n'
while True:
try:
# 接收小于 1024 字节的数据
# 读取接收到的数据并写入文件
total_data = []
print("\nClient读入数据准备")
while True:
# 对于接收到的数据要用decode()把utf-8解码转成unicode编码
data = self.s.recv(1024).decode()
# 收到End表明接收数据完成
if End in data:
total_data.append(data[:data.find(End)])
break
total_data.append(data)
print("\nClient开始写入文件")
data = ''.join(total_data) # join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
# 文件要与程序文件放在一个目录下
with open('Client.txt', 'a') as f:
f.write(data)
except socket.error:
# 自动重连
self.s = self.do_connect(self.host, self.port)
except IOError:
print('\n写入文件错误')
# except:
# print('\n其他错误发生')
time.sleep(1)
# 多线程调用
def my_thread(self, name):
if name == 'send':
self.send_msg()
else:
if name == 'recv':
self.receiver_msg()
else:
print('error: The format is not recognized!')
然后就是调用类名和函数并给参数就可以了
Server:
因为就是用来测试Client是否有效的,所以基本就参考着菜鸟教程写的,只是根据需要改动了不重要的地方。