У меня есть стандартная настройка разветвления 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;
}