Java 客户端抛出 SocketException : Connection reset when receiving data from C server. 为什么?

标签 java c sockets java-io

我有一个用 C 编写的 TCP/IP 服务器程序和一个用 Java 编写的相应客户端:

C 服务器

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>


#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 0

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


    printf("ISV_APP: Initiating TCP/IP networking.\n");

    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};



    // Creating socket file descriptor.
    if((server_fd = socket(AF_INET, SOCK_STREAM,0)) == 0)
    {
        printf("TCP/IP: Initiation of server socket file descriptor failed.\n" );
        return -1;
    }
    printf("TCP/IP: Initializing server socket.\n" );

    // Forcefully attaching socket to the connection port.
    if(setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
    {
        printf("TCP/IP: Error with setsockopt call occured.\n" );
        return -1;
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    printf("TCP/IP: Socket options have been set.\n" );

    // Binding the socket.
    if(bind(server_fd, (struct sockaddr *)&address, sizeof(address)) <0){
        printf("TCP/IP: Failed to bind socket.\n" );
        return -1;
    }
    printf("TCP/IP: Socket bound to port.\n" );

    // Listen for connections
    if(listen(server_fd, 3) < 0){
        printf("TCP/IP: Failed to listen for incoming connections.\n" );
        return -1;
    }

    // Print the assigned port and address so that client knows how to connect.
    struct sockaddr_in sin;
    socklen_t len = sizeof(sin);
    if (getsockname(server_fd, (struct sockaddr *)&sin, &len) == -1){
        printf("Failed to read port number.\n" );
    }
    else{
        // Print port
        unsigned int my_port = ntohs(sin.sin_port);
        char my_port_str[6]; 
        sprintf(my_port_str, "%d", my_port);
        printf("\nINFO: Socket bound to port: " );
        printf(my_port_str);
        printf("\n");

        // Print address
        char my_ip[16];
        inet_ntop(AF_INET, &sin.sin_addr, my_ip, sizeof(my_ip));
        printf("INFO: Server IP Address: ");
        printf(my_ip);

        printf("\n");
        printf("\nServer is listening for incoming connections...\n" );

    }

    // Accept connection
    if((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen))<0){
        printf("TCP/IP: Failed to accept incoming connection.\n" );
        return -1;
    }
    printf("TCP/IP: Connection successfully established.\n" );
    printf("\n");
    fflush(stdout);

    // Connection successful. You can send and receive data now. 


    // Get message from client.
    printf("Waiting for message from client...\n");
    valread = read(new_socket, buffer, 1024);
    printf("FROM CLIENT: %s\n", buffer);

    // Pass message to client.
    printf("Sending message to client...\n");
    char *hello = "serversayshello";
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");


    // Close file descriptors and end program.
    close(new_socket);
    close(server_fd);
    printf("End of program.");
    exit(EXIT_SUCCESS);
}

Java 客户端

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

public class MobileClientPrototype {

    public static void main(String[] args) throws IOException{

        // Used to get user input. 
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Please enter IP Address:");
        String host = inFromUser.readLine();

        System.out.print("Please enter port number:");
        int port = Integer.parseInt(inFromUser.readLine());

        // Initialize Socket
        Socket clientSocket = new Socket(host, port);

        // Streams for communication with server
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

        // Ask user for string message which will be sent to server
        String sentence;
        System.out.print("\nPlease enter message:\n");
        sentence = inFromUser.readLine();

        // Send message to server
        outToServer.writeBytes(sentence + '\n');
        System.out.print("Message sent!\n\n");

        // Wait for response message from server        
        String responseSentence;
        System.out.print("Awaiting response...\n");
        responseSentence = inFromServer.readLine();
        // Print response
        System.out.println("RESPONSE FROM SERVER:\n" + responseSentence);

        // Close socket and end program
        System.out.print("\nTerminating connection...");
        clientSocket.close();
        System.out.print("\nEnd of program.");
    }
}

场景

我在本地机器上同时运行服务器和客户端程序。对于客户端,我输入 127.0.0.1 作为 IP 和服务器打印的端口号。建立连接后,您可以在客户端输入一条消息,该消息将发送到服务器。之后,服务器以 serversayshello 响应。

它适用于一些短字符串,例如,我可以传输hello:

Screenshot 1

但是,对于一些较长的字符串,客户端一收到服务器的响应就会抛出 SocketException: Connection reset

在这里,我试图从客户端向服务器发送问候。这是发生了什么:

Screenshot 2

同样值得注意的是,服务器显然没有收到完整的消息,因为它只打印了hello from

错误

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:210)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at MobileClientPrototype.main(MobileClientPrototype.java:38)

传输似乎适用于短字符串,如“hello”、“123456”、“foo”、“bar”、“g g”等。

一些不起作用的字符串是: “你好”(大写 H)、“来自客户的问候”、“foobarfoobarfoobar”。

除此之外,我还没有想出一个模式。

是什么导致客户端在传输这些较长的消息时抛出异常?

最佳答案

您无法确定 read() 是否在一次调用中返回所有内容(除非您查看读取的数据的内容或 read() 的返回值>), 很多时候它会返回部分数据,你将不得不再次 read() 来读取剩余的数据

套接字通信的推荐方式是事先决定预期的数据,您可以决定使用固定长度的数据并继续调用 read() 直到总字节数(将读取的返回值加起来() 调用,当大于零时表示成功读取的字节数)读取等于您预先确定的固定长度,或者您可以决定期待一个新行来指示数据结束并继续循环读取直到您收到 '\n'

关于Java 客户端抛出 SocketException : Connection reset when receiving data from C server. 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50738239/

相关文章:

java - 冷聚变 : Runtime show logs on CF page just like Console or Putty

c# - 比较通过 NetworkStream 发送到服务器/从服务器发送的值

C 用指针在字符串中查找子字符串

java - 是否可以在logback中将日志写入scr/main/resources?

java - 通过扬声器播放麦克风中的音频

java - 我怎样才能用计算机程序解决 Log Pile 木制拼图?

c - 我的 sqlite 数据库文件的位置在哪里?

按列公式 CPLEX - 在列中添加新的约束集

c# - 在 Linux 上从 .NET Core 手动调用 recvmsg 不会返回

java - 如何将 "variables"WHERE 子句注入(inject)查询?