Передача файлов с клиента C ++ на сервер Java - PullRequest
1 голос
/ 13 января 2010

У меня есть клиент c ++, которому нужно отправить файл на сервер c ++. Я разделяю файл на части байтов PACKET_SIZE (= 1024) и отправляю их через сокет TCP. На стороне сервера я читаю не более PACKET_SIZE байтов в буфер. Когда клиент отправляет файлы, размер которых меньше PACKET_SIZE, сервер получает больше байтов, чем отправлено. Даже когда я ограничиваю количество байтов размером файла, файлы различаются. Я знаю, что проблема не связана с клиентом, потому что я проверил его на сервере C ++, и он работает безупречно.

Спасибо.

Сервер:

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

}

Клиент:

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

Ответы [ 3 ]

0 голосов
/ 19 января 2010

Одна проблема, которую я вижу, заключается в том, что, по-видимому, вы предполагаете, что если при отправке возвращается не ошибка, то он отправил весь кусок, который вы запросили для отправки. Это не обязательно так, особенно с потоковыми сокетами. Насколько большие пакеты вы отправляете и сколько? Наиболее вероятная причина, по которой это может произойти, - заполнение sndbuf для сокета, а для вашего сокета _sd установлено неблокирование. Я не уверен (зависит от реализации стека), но я полагаю, что это также может произойти, если окно передачи TCP было полно для вашего соединения, и tcp не смог поставить в очередь весь ваш пакет.

Возможно, вам следует выполнить цикл отправки, пока не будет отправлено значение max.

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
   }
}
0 голосов
/ 21 января 2010

код не полный. Например. Вы пропустили отправку имени файла и размера файла, а также анализ этих значений. Эти значения правильны? Если нет, сначала убедитесь, что эти значения верны, прежде чем приступить к дальнейшему расследованию.

0 голосов
/ 13 января 2010

Закрывающий сокет закрыт в конце файла или следующий файл передается через тот же сокет? Если потоковый файл содержит более одного файла, вы можете выбрать данные из следующего файла, если у вас неправильная конечность для размера файла в recvHeader(), т.е. вы отправляете файл длиной 0x0102 и пытаетесь прочитать один из файлов длины 0x0201.

Другой вопрос, почему вы предоставляете максимум для первого чтения, а не для следующих чтений в одном и том же файле?

...