gpt4 book ai didi

python - 如何保持Python服务器连接打开,直到客户端完成它?

转载 作者:太空宇宙 更新时间:2023-11-03 19:31:36 25 4
gpt4 key购买 nike

我有一个标准的 fork TCPServer 设置,用于接收传入请求并将文件发送回客户端。服务器似乎正在发送所有数据,但我检查了客户端收到的字节数!=发送的字节数。

经过进一步调查,接收方法客户端指示服务器提前关闭连接 - 导致接收失败。

然后我将服务器修改为在发送文件后休眠几秒钟 - 保持套接字打开足够长的时间以便客户端接收然后关闭它。这可行,但在我看来这是非常黑客的,因为很难预测线程在关闭套接字之前应该休眠多长时间。

我尝试设置 SO_LINGER 服务器端来保持连接处于事件状态,但它没有帮助 - 尽管我认为应该这样做。

必须有更好的方法来阻止,直到客户端完全接收到文件。我需要做什么才能保证套接字在客户端收到所有数据之前不会关闭?

服务器

class ForkingTCPRequestHandler(SocketServer.BaseRequestHandler):
def createSPP(self, dataLen, success):
SPPStruct = struct.Struct('I?')
values = (socket.htonl(dataLen), success,)
packed_data = SPPStruct.pack(*values)
return packed_data

def handle(self):
"""Enabling SO_LINGER to keep connection alive doesn't help"""
self.request.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 5))

"""Send a packet to the client so it knows the length of incoming data"""
spp = self.createSPP(os.path.getsize(FILE_NAME), 1)
self.request.sendall(spp)

"""Sending the file, finish() is automatically called after this."""
f = open(FILE_NAME, 'rb')
fileData = f.read()
self.request.sendall(fileData)
f.close()

def finish(self):
"""Sleep until the file is fully received by the client.
Sleeping keeps the connection open. BaseRequestHandler automatically
closes the connection when finish() returns. This works but is not a
robust solution."""
time.sleep(5)

class ForkingTCPServer(SocketServer.ForkingMixIn, SocketServer.TCPServer):
pass

if __name__ == '__main__':
try:
server = ForkingTCPServer((HOST, PORT), ForkingTCPRequestHandler)
except socket.error as e:
sys.exit(1)

try:
server.serve_forever()
except KeyboardInterrupt:
server.shutdown()
sys.exit(0)

客户端连接到服务器

    // Establishes a standard TCP connection
memset(&targetAddr, 0, sizeof(targetAddr));
targetAddr.sin_family = AF_INET;
targetAddr.sin_port = htons(atoi(port));
bcopy(hostdetails->h_addr, (char *)&targetAddr.sin_addr, hostdetails->h_length);

sock = socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0) {
return -1;
}

rc = connect(sock, (struct sockaddr *)&targetAddr, sizeof(targetAddr));
if (rc < 0) {
close(sock);
return -1;
}

客户接收

    // Receiving spp (server side) known as symProcPacket (client side)
// symProcPacket contains the length of the file that will be sent next
// Receiving this packet is always successful
typedef struct SymProcessPacket {
u_int32_t totalDataLen;
BOOL processingSuccessful;
} SymProcessPacket;

tempBuf = (char *)malloc(sizeof(SymProcessPacket));
recvBytes = recv(s, tempBuf, sizeof(SymProcessPacket), 0);
if (recvBytes < 0) {
goto processingError;
}

memcpy(&symProcPacket, tempBuf, sizeof(SymProcessPacket));
free(tempBuf);

// Receiving the file
// Receive chunks and put in a buffer until entire file is received
tempBuf = (char*) malloc(sizeof(char)*ntohl(symProcPacket.totalDataLen));
totalRecv = 0;
recvBytes = 0;

while (totalRecv < ntohl(symProcPacket.totalDataLen)) {
recvBytes = recv(sock, tempBuf+totalRecv, (1<<14), 0);
if (recvBytes < 0) {
// RecvBytes returns -1, which is an error before getting all the data
// It gets a "Connection was reset by peer" error here, unless the server
// sleeps for a bit. It means the server closed the connection early.
printf("Error: %s", errtostr(errno));
goto errorImporting;
}
totalRecv += recvBytes;
}

最佳答案

我正在跳过你的代码部分。我将专注于您的问题,接收完整的文件。一种很酷的方法是采用 HTTP 方式。首先,只需发送要发送的字节数,以便接收端将从套接字接收到该数量的字节数。因此,只需向接收器发送少量附加数据即可完成工作。

发件人:

  • 发送要发送的文件的大小
  • 发送文件数据

接收者:

  • 接收文件大小
  • 接收数据直到 len(data)==size_received

关于python - 如何保持Python服务器连接打开,直到客户端完成它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5533092/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com