Java 服务器套接字连接重置

Wik*_*cki 3 java sockets networking

当我的第二个客户端连接到我的服务器时,我收到此错误:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:200)
    at java.base/java.io.DataInputStream.readLine(DataInputStream.java:518)
    at Main.main(Main.java:24)
Run Code Online (Sandbox Code Playgroud)

我不知道我做错了什么。

第一个客户端工作正常

我的代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class Main {
    public static void main(String[] args) throws IOException {
         ServerSocket serverSocket = new ServerSocket(50505);;
         Socket socket;
         while (true) {
             socket = serverSocket.accept();
             while(socket.isConnected()) {
                 String v;
                 DataInputStream in;
                 InputStream in_sock;
                 in_sock = socket.getInputStream();
                 in = new DataInputStream(in_sock);
                 v = in.readLine();
                 System.out.println(v);
                 OutputStream output = socket.getOutputStream();
                 DataOutputStream out = new DataOutputStream(output);
                 out.writeChars("123\n");
                 out.writeChars("123\n");
                 out.writeChars("123\n");
             }
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

PS:如何在stackoverflow上分享错误?喜欢代码?

小智 5

所以像其他一些人所说的那样,最大的问题是由于缺乏多线程,您的服务器只能接受一个连接。

现在您的服务器正在等待与指定端口的连接

socket = serverSocket.accept();
Run Code Online (Sandbox Code Playgroud)

然后,当您的套接字仍然连接时,您从套接字读取一行,将其打印到 System.out,然后在循环中写回套接字。现在这出现了问题,因为下次客户端尝试连接到您的 serverSocket 时,它无法再接受连接,因为您的代码陷入了从一个 Socket 读取和写入数据的循环中。

解决这个问题的方法是按照 Milen 上面提到的方式引入多线程。

您的代码应该如下所示。

public class Main {
    public static void main(String[] args) throws IOException {
         ServerSocket serverSocket = new ServerSocket(50505);
         while (true) {
             Socket socket = serverSocket.accept();
             SocketHandler h = new SocketHandler(socket);
             h.start();
         }
    }
}

public class SocketHandler extends Thread{

    Socket clientSock;
    public SocketHandler(Socket sock){
        clientSock = sock;
    }

    public void run(){
        while(clientSock.isConnected()) {
            String v;
            DataInputStream in;
            InputStream in_sock;
            in_sock = socket.getInputStream();
            in = new DataInputStream(in_sock);
            v = in.readLine();
            System.out.println(v);
            OutputStream output = socket.getOutputStream();
            DataOutputStream out = new DataOutputStream(output);
            out.writeChars("123\n");
            out.writeChars("123\n");
            out.writeChars("123\n");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这段代码有一个接受连接的循环,并为每个连接产生一个新线程!

我建议看一些东西。首先,如果您检查 ServerSocket 的 Java 文档,您将看到此构造函数

ServerSocket(int port, int backlog)
Creates a server socket and binds it to the specified local port number, with the specified backlog.
Run Code Online (Sandbox Code Playgroud)

积压是服务器套接字可以保留并存储在某种缓冲区中直到它们可以被接受的传入连接的数量。如果当您的接受循环处于创建套接字处理程序的中间时客户端正在连接,这将非常有用。我建议将它放在您期望的最大客户数量上。

其次,在 Javadocs 中查找 Thread 类。要成功扩展 Thread,您需要覆盖 run()。此方法是线程将使用的方法。要生成线程,请调用 ThreadObject.start()。您可以将 start() 视为只是调用 run()。