1

I have a standard forking TCPServer setup that receives incoming requests and sends back a file to a client. The server appears to be sending all the data, but I've checked client side that the bytes received != the bytes sent.

After further investigation, the receive method client side indicated that the server was closing the connection early - causing the receive to fail.

So then I modified the server to sleep for a couple seconds after sending the file - keeping the socket open long enough for the client to receive and then closing it. This works but it's very hackish in my opinion because it's hard to predict how long the thread should sleep before closing the socket.

I have tried setting SO_LINGER server side to keep the connection alive instead, but it doesn't help - even though I think it should.

There has to be a better way to block until the client fully receives the file. What do I need to do to guarantee the socket does not close until the client receives all the data?

Server

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) 

Client Connecting to the Server

 // 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; } 

Client Receiving

 // 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; } 
8
  • sendall will already block. Your code works for me. how are you attempting to connect to this? Commented Apr 3, 2011 at 23:28
  • Yea, socket.sendall() and send socket.send() technically should block, but I'm still getting a "Connection was reset by peer" error client side when I'm receiving data - so it's not blocking for some reason since the server closes the connection before the client gets all the data. Commented Apr 4, 2011 at 0:23
  • and what function actually returns an error? Commented Apr 4, 2011 at 0:29
  • Are the client and server on different sides of an ISP provided connection? Some braindead ISP's inject resets into the packet stream for reasons that are completely inscrutable. Often it is sufficient to block those resets at the router. Commented Apr 4, 2011 at 0:46
  • @winston I just added the client receiving part. The server sends a packet with the size of the file, the client recv() until it gets all the chunks. @TokenMacGuy That's interesting. I never knew that was even possible. But the client and server are running in my home network, different machines, same ISP. Commented Apr 4, 2011 at 2:15

2 Answers 2

1

I am skipping your code part. I will just stay focused on the your problem, receiving complete file. One cool way would be adapting HTTP way. At first, just send the amount of bytes you are going to send so that the receiver end will receive from socket just up to that amount. So, just sending little additional data to receiver will do the work..

sender:

  • Send the size of file to be sent
  • Send the file data

receiver:

  • Receive file size
  • Receive data until len(data)==size_received
Sign up to request clarification or add additional context in comments.

Comments

0

I can't figure out why sleeping has solved anything.

But I think python in sending 5 bytes and C++ is reading 8 bytes.? in python takes on byte. BOOL I believe is typedefed as an int and takes probably 4 bytes.

In general reading/writing structs to sockets is discouraged.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.