在后端与聚合端的交互中存在这样一个操作,就是后端需要把torch包之下通过将模型load_state_dict提取到的模型参数通过网络送到聚合端进行聚合,而聚合端在进行聚合操作后也需要将网络参数字典返还到后端。
我们的项目采用了python标准库中的socket以及pickle来进行这样的操作,其好处是两边只要使用相同的class对象即可进行对象的传输。
而目前我们遇到的问题在于传输较大的字节流时,猜测是由于传输与接收速度不匹配的缘故,会出现一个提示socket pickle data was truncated的错误,意味数据被截断。起初我们为了能够一次性接收所有数据,就将缓冲区设置得很大。(如下图代码)
Socket.recv(999999)
结果是有些时候可以完全接收,有些则会报socket pickle data was truncated,这意味在这样的设计下这样的错误的出现是随机的,于是后面我们重新设计了一个机制,不仅可以针对不同大小的字节流,也能保证出现数据截断问题时可以重传。(其实类似tcp的思想)
代码如下:
# 参数为socket以及要发送的数据对象
def muteki_send(clientSocket, message):
temp_pickle = pickle.dumps(message)
# 先发送大小信息
size = sys.getsizeof(temp_pickle)
size = pickle.dumps(size)
clientSocket.sendall(size)
# 接收确认信息
ack = clientSocket.recv(1024)
# 当ack为true,循环发送数据直到ack改为false
while True:
# 数据发送
clientSocket.sendall(temp_pickle)
# 大小比对信息接收
# 接收大小确认信息,若为true break,若为false重发
sizeACK = clientSocket.recv(1024)
sizeACK = pickle.loads(sizeACK)
if sizeACK:
break
def muteki_recv(clientSocket):
# 接收大小信息
size = clientSocket.recv(1024)
size = pickle.loads(size)
# send确认信息
ack = pickle.dumps(True)
clientSocket.sendall(ack)
# 开始循环接收数据,直到数据大小一致
# try:
sizeJudge = True
finalData = ''
while sizeJudge:
data = clientSocket.recv(1024)
time.sleep(0.1)
temp = sys.getsizeof(data)
judge = (sys.getsizeof(data) == 1057)
if judge:
while True:
packet = clientSocket.recv(2048)
time.sleep(0.0005)
data += packet
if sys.getsizeof(packet) < (2048 + 33):
break
# 比对大小信息,若一致则发送true break,不一致返回false重新接收
if sys.getsizeof(data) == size:
sizeACK = pickle.dumps(True)
clientSocket.sendall(sizeACK)
finalData = data
break
else:
sizeACK = pickle.dumps(False)
clientSocket.sendall(sizeACK)
continue
return finalData
这样双方就能以大小为依据确认是否出现丢包,从而在出现错误时进行重传。