最近写了一个socket示例,可以实现两个功能:
- 一个服务端同时服务多个客户端:采用带返回值的多线程
2.客户端发现服务端断开后,自动重连
Server端代码
import socket
import threading
import time
class MyThread(threading.Thread):
"""多线程有返回值时,使用该类"""
def __init__(self, func, args=()):
super(MyThread, self).__init__()
self.func = func
self.args = args
def run(self):
self.result = self.func(*self.args)
def get_result(self):
try:
return self.result
except Exception:
return None
def recv_data(sock, nonblock_mark):
if nonblock_mark:
'''非阻塞式接受信息'''
print("start to get message unblock")
try:
data = sock.recv(1024, 0x40)
except Exception as e:
print("no message recieved!!", e, "will recieve 3s later")
time.sleep(3)
data ="null"
else:
'''阻塞式接受信息'''
print("start to get message block")
try:
data = sock.recv(1024)
except Exception as e:
print("connection broken!!!", e)
data = None
return data
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) #设置端口复用
s.bind(('', 123456))
s.listen(5)
print("waiting for connection!!!")
while True:
sock, addr = s.accept()
print("receive connection from %s:%s" % addr)
while True:
t = MyThread(recv_data, args=((sock, 1)))
t.start()
t.join()
data = t.get_result()
print(data)
print("length of data:", len(data), time.time())
if data == 'exit' or not data:
print("connection from %s:%s closed" % addr)
sock.close()
break
elif data == "null":
print("receieve no data on nonblocking mode!!")
continue
s.close()
Client端代码
# 导入 socket、sys 模块
import socket
import struct
import time
def doConnect(host, port):
# 创建 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
s.connect((host, port))
except Exception as e:
print("connection broken:", e, "will reconnect 3s later!!")
time.sleep(3)
else:
break
return s
# 获取本地主机名
host = "127.0.0.1"
# 设置端口号
port = 123456
# 连接服务,指定主机和端口
s = doConnect(host, port)
while True:
data = input("please input anykey to continue:")
if task_type:
# 发送消息:如果连接失败,重连服务器,重新发送
try:
s.send(data.edcode())
except socket.error as e:
print("connection borken:", e, "\nwill reconnect 3s later")
s = doConnect(host, port)
s.send(data)
else:
continue
s.close()
当然,这段代码也是有缺陷的:
1.标准代码应该采用类的方式来写,本人类的基础比较弱,有待加强
2.一个服务端同时服务多个客户端,官方推荐采用select模块
3.客户端的自动重连功能有缺陷:当服务端断开30s之内,客户端依然认为服务端在线,这个bug暂时没找到解决方案
参考资料:
python-socket客户端设置自动重连,服务端线程收发消息
Python socket 怎么判断连接断开
Python-select详解(select、epoll)