views:

393

answers:

3

Hi,

I have a c++ client which needs to send a file to a c++ server. I'm splitting the file to chunks of PACKET_SIZE (=1024) bytes and send them over a TCP socket. At the server side I read at most PACKET_SIZE bytes to a buffer. When the client sends files which are less than PACKET_SIZE, the server receives more bytes than sent. Even when I limit the number of bytes to be exactly the size of the file, the files differ. I know the problem does not have to do with the client because I've tested it with a c++ server and it works flawlessly.

Thanks.

Server:

public void run()  {  
     DataInputStream  input = null;
     PrintWriter output = null;
     try {
         input = new DataInputStream (_client.getInputStream());
     }         
     catch (Exception e) {/* Error handling code */}

     FileHeader fh =  recvHeader(input);      
     size = fh._size;
     filename = fh._name;

     try {
         output = new PrintWriter(_client.getOutputStream(), true);
     }

     catch (Exception e) {/* Error handling code */}

     output.write(HEADER_ACK);
     output.flush();

     FileOutputStream file = null;
     try {
         file = new FileOutputStream(filename);
     }

     catch (FileNotFoundException fnfe) {/* Error handling code */}

     int total_bytes_rcvd = 0, bytes_rcvd = 0, packets_rcvd = 0;
     byte [] buf = new byte [PACKET_DATA_SIZE];

     try {
        int max = (size > PACKET_DATA_SIZE)? PACKET_DATA_SIZE: size;
        bytes_rcvd = input.read(buf,0, max);
        while (total_bytes_rcvd < size) {
                if (-1 == bytes_rcvd) {...}

                ++packets_rcvd;
            total_bytes_rcvd += bytes_rcvd;
            file.write (buf,0, bytes_rcvd);
            if (total_bytes_rcvd < size)        
                   bytes_rcvd = input.read(buf);
            }    

        file.close();

     }

     catch (Exception e) {/* Error handling code */}

}

Client:

char packet [PACKET_SIZE] ;  
file.open (filename, ios::in | ios::binary);//fopen (file_path , "rb");
int max = 0;
if (file.is_open()) {
    if (size > PACKET_SIZE)
        max =  PACKET_SIZE;
    else
        max = size;
    file.read (packet , max);
}

else {...}

int   sent_packets = 0;
while (sent_packets < (int) ceil (((float)size)/PACKET_SIZE) ) { 
        _write=send(_sd , packet, max,0);
        if (_write <0) {...}
        else {
             ++sent_packets;
            if (size > PACKET_SIZE* sent_packets) {
                if (size - PACKET_SIZE* sent_packets >= PACKET_SIZE)
                    max =  PACKET_SIZE;
                else
                    max = size - PACKET_SIZE* sent_packets;
                file.read (packet , max);
            }
        }
}
A: 

Is the sending socket closed at the end of the file, or is the next file streamed over the same socket? If more than one file is streamed, you could pick up data from the next file if you have the endedness wrong for the file size in recvHeader(), i.e. you send a file of length 0x0102 and try to read one of length 0x0201.

Other question, why do you provide a max for the first read, but not for the following reads on the same file?

rsp
A: 

One issue I see is that it appears that you assume that if the send returns a non-error, that it sent the entire chunk you requested it to send. This is not necessarily true, especially with stream sockets. How large are the packets you are sending, and how many? The most likely reason this could occur would be if the sndbuf for the socket filled, and your socket _sd is set to non-blocking. I'm not positive (depends on stack implementation), but I believe it could also likely occur if the TCP transmit window was full for your connection, and tcp couldn't enqueue your entire packet.

You should probably loop on the send until max is sent.

Thusly:

int send_ct=0;
while( (_write = send(_sd, packet + send_ct, max-send_ct, 0)) > 0) {
   send_ct += _write;
   if(send_ct >= max) {
      break;
   } else {
      // Had to do another send
   }
}
TomT the Weatherman
A: 

Hi ... the code is not complete. E.g. you have omitted the sending of the filename and the filesize, as well as the parsing of those values. Are those values correct? If not first ensure that these values are the right ones before investigating further.

Gizmomogwai