2013-04-17 2 views
0

Я пытаюсь написать сервер-клиентское приложение для передачи файлов. Клиент написан на Java, а сервер написан на C++.Сброс соединения с помощью peer: ошибка записи сокета C++ - java

К сожалению, я следующее сообщение об ошибке:

java.net.SocketException: Connection reset by peer: socket write error"

Вот мой код клиента:

import java.io.*; 
import java.net.Socket; 


public class Proba_binar 
{ 
    public static void main(String[] args) 
    { 
     byte[] buffer = null; 
     byte[] auxByte = new byte[1000]; 
     String fileName = "1.jpg"; 
     File a_file = new File(fileName); 
     try 
     { 
      // Create a socket 
      Socket socket = new Socket("192.168.14.146", 8888); 

      BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 

      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 


      // Read file 
      FileInputStream fis = new FileInputStream(fileName);  
      int length = (int)a_file.length(); 
      buffer = new byte[length]; 
      fis.read(buffer); 
      fis.close(); 

      // Send file length 
      System.out.println("length = " + Integer.toString(length)); 
      out.write(Integer.toString(length) + "\n"); 
      out.flush(); 

      // Send file 
      int imageSize = buffer.length; 
      char[] auxChar = new char[1000]; 
      int nr_transf = imageSize/1000; 
      int rest_byte = imageSize % 1000; 
      System.out.println("nr_transf = " + nr_transf); 

      for(int j = 0; j < nr_transf; j++) 
      { 
       // send series of 1000 bytes 
       for(int i = 0; i < 1000; i++) 
       { 
        auxChar[i] = (char)buffer[j*1000+i]; 
        auxByte[i] = buffer[j*1000+i]; 
       } 
       out.write(auxChar); 
       out.flush(); 
      } 

      // send last bytes 
      for(int i = 0; i < rest_byte; i++) 
      { 
       auxChar[i] = (char)buffer[1000*nr_transf+i]; 
       auxByte[i] = buffer[1000*nr_transf+i]; 
      } 
      out.write(auxChar, 0, rest_byte); 
      out.flush(); 

      out.close(); 
      in.close(); 
      socket.close(); 
      System.out.println("Transfer finished!"); 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

И код сервера:

int main(int argc , char *argv[]) 

{ 

    WSADATA wsa; 

    SOCKET s , new_socket; 

    struct sockaddr_in server , client; 

    int c, bytecount, nr_transf, rest_byte, i; 

    int recv_size, file_size; 

    char message[1000]; 

    char buffer[1000]; 
    int buffer_len = 1000; 
    FILE *f = fopen("out.jpg", "wb"); 

    printf("\nInitialising Winsock..."); 
    if (WSAStartup(MAKEWORD(2, 2),&wsa) != 0) 
    { 
     printf("Failed. Error Code : %d",WSAGetLastError()); 
     return 1; 
    } 

    printf("Initialised.\n"); 

    //Create a socket 
    if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
    { 
     printf("Could not create socket : %d" , WSAGetLastError()); 
     getch(); 
     return 0; 
    } 

    printf("Socket created.\n"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(8888); 

    //Bind 
    if(bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) 
    { 
     printf("Bind failed with error code : %d" , WSAGetLastError()); 
     getch(); 
     return 0; 
    } 

    puts("Bind done"); 

    //Listen to incoming connections 
    listen(s, 3); 

    //Accept and incoming connection 
    puts("Waiting for incoming connections..."); 

    c = sizeof(struct sockaddr_in); 
    new_socket = accept(s, (struct sockaddr*)&client, &c); 
    if (new_socket == INVALID_SOCKET) 
    { 
     printf("accept failed with error code : %d", WSAGetLastError()); 
     getch(); 
     return 0; 
    } 

    puts("Connection accepted"); 

    //Receive FILE DIMENSION from client 

    if((recv_size = recv(new_socket, message, 1000, 0)) == SOCKET_ERROR) 
    { 
     puts("recv failed"); 
     getch(); 
    }  
     message[recv_size] = '\0'; 
    file_size = atoi(message); 

    printf("\nfile_size = %d", file_size); 

    nr_transf = file_size/1000; 
    rest_byte = file_size % 1000; 

    //Receive FILE from client 

    for(i = 0; i < nr_transf; i++) 

    { 

     // receive 1000 bytes 

     if((bytecount = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR) 

     { 

      printf("Receive failed auxChar"); 

      getch(); 

      return 0; 

     } 

     fwrite(buffer, 1, buffer_len, f); 

    } 

    // receive last bytes 

    if((bytecount = recv(new_socket, buffer, rest_byte, 0)) == SOCKET_ERROR)  

    { 

     printf("Receive failed rest_byte"); 

     getch(); 

     return 0; 

    } 

    fwrite(buffer, 1, rest_byte, f); 

    fclose(f); 

    printf("Receive finished!"); 





    closesocket(s); 

    WSACleanup(); 



    getch(); 

    return 0; 

} 

Я сделал эквивалентный сервер в Java и работает отлично. Я не знаю, в чем проблема в версии C++. Спасибо заранее!

ответ

0

recv() не гарантирует, что он будет читать все запрошенные:

...calling recv will return as much data as is currently available—up to the size of the buffer specified...

Это означает, что цикл for/recv это неправильно структурированы и это, вероятно, так что сервер считает, что прочитал все данные но это не так. Это приводит к тому, что сервер закрывает сокет до того, как клиент отправит все данные, что приведет к ошибке, сообщаемой клиентом Java.

Пример (непроверенная) перестройка цикла recv:

int totalBytesRead = 0; 
int bytesRead; 
while (totalBytesRead < file_size) 
{ 
    if((bytesRead = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR) 
    { 
     /* Handle failure. */ 
     break; 
    } 

    if (bytesRead != fwrite(buffer, 1, bytesRead, f)) 
    { 
     /* Handle failure. */ 
     break; 
    } 

    totalBytesRead += file_size; 
} 

Помните, что соединенные сокеты поток на основе, используя mutilple send() S не означает, что соответствующие recv() ы будут считывать данные в том же «кусках как они были посланы. В дополнение к уже упомянутой ошибке поиска содержимого, это в равной степени относится к чтению размера файла. Нет гарантии, что весь размер файла будет считан.

Я бы рекомендовал разработать простой протокол, чтобы обеспечить правильное чтение различных типов данных. Например, клиент отправляет:

<file_size>\n<file_content>

сервер считывает все данные до символа новой строки и преобразует их в размер файла. Тогда сервер точно знает, что он имеет правильный размер файла. Затем сервер считывает из сокета file_size байт. Наконец, сервер отвечает, чтобы указать успех или неудачу:

success\n

клиент считывает до символа новой строки, чтобы получить ответ.

+0

Я обновил код сервера, но у меня все еще такая же ошибка. По сути, клиент отправляет байты file_size (я тестировал, если сервер получает первое сообщение, содержащее целое число «file_size»), и сервер получает быстрее некоторые случайные байты и закрывает сокет ... Наконец, клиент выдает одну и ту же ошибку: «Сброс соединения с помощью одноранговой сети: ошибка записи сокета ". Я действительно не знаю, что происходит ... – adrian2012

+0

Я удалил свой код клиента для следующего: «while ((bytesReceived = input.read (buffer))> 0) { out.write (buffer, 0, bytesReceived) System.out.println (bytesReceived); break; } «Я теперь отлично работает. Спасибо за вашу помощь! – adrian2012

Смежные вопросы