0

我正在尝试编写用于文件传输的服务器客户端应用程序。客户端是用 Java 编写的,服务器是用 C++ 编写的。

不幸的是,我有以下错误:

java.net.SocketException:对等方重置连接:套接字写入错误“

这是我的客户代码:

 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++版本是什么问题。提前致谢!

4

1 回答 1

0

recv()不保证它将读取请求的所有字节:

...调用 recv 将返回当前可用的尽可能多的数据——最大为指定缓冲区的大小...

这意味着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()的 s 将读取与发送时相同的“块”中的数据。除了已经提到的数据内容检索错误之外,这同样适用于文件大小的读取。无法保证会读取整个文件大小。

我建议设计一个简单的协议来确保正确读取不同类型的数据。例如,客户端发送:

<文件大小>\n<文件内容>

服务器读取所有数据直到换行符并将其转换为文件大小。然后服务器确定它具有正确的文件大小。然后服务器file_size从套接字读取字节。最后,服务器响应指示成功或失败:

成功\n

客户端读取换行符以获取响应。

于 2013-04-17T08:16:40.143 回答