如何重现“java.net.SocketException.Connection重置”?

问题描述 投票:0回答:5

我正在尝试重现“java.net.SocketException.Connection Reset”异常。

想知道是否有任何程序可以帮助我模拟它。我尝试遵循服务器和客户端程序来查看是否可以模拟,但我无法得到任何异常。我正在使用java8。

服务器代码-

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;


public class SimpleServerApp {

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

        new Thread(new SimpleServer()).start();

    }

    static class SimpleServer implements Runnable {

        @Override
        public void run() {

            ServerSocket serverSocket = null;

            try {
                serverSocket = new ServerSocket(3333);
                serverSocket.setSoTimeout(0);

                //serverSocket.
                while (true) {
                    try {
                        Socket clientSocket = serverSocket.accept();

                        BufferedReader inputReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                        System.out.println("Client said :"+ inputReader.readLine());

                    } catch (SocketTimeoutException e) {
                        e.printStackTrace();
                    }
                }

            }catch (Exception e) {
                e.printStackTrace();
                System.out.println(" EXCEPTION " + e.getStackTrace());
            }/*catch (IOException e1) {
                e1.printStackTrace();
            }*/ /*finally {
                try {
                    if (serverSocket != null) {
                        serverSocket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }*/

        }

    }
}

客户端代码 -

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;


public class SimpleClientApp {

    public static void main(String[] args) {

        new Thread(new SimpleClient()).start();

    }

    static class SimpleClient implements Runnable {

        @Override
        public void run() {

            Socket socket = null;
            try {

                socket = new Socket("localhost", 3333);


                PrintWriter outWriter = new PrintWriter(socket.getOutputStream(), true);

                System.out.println("Wait");

                Thread.sleep(20000);
                //System.exit(0);
                //throw new Exception("Random exception");
                //socket.close();

                outWriter.println("Hello Mr. Server!");

            }catch (SocketException e) {
                e.printStackTrace();
            }catch (InterruptedException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } /*finally {

                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }


            }
*/      }

    }

}

场景1。

  • 本地启动服务器程序。
  • 本地启动客户端程序。
  • 突然关闭客户端程序(Ctrl C)-我刚刚得到输出 服务器程序“客户端说:null”

场景2.

  • 本地启动服务器程序。
  • 本地启动客户端程序。
  • 客户端连接到服务器,然后在客户端程序等待时突然关闭服务器程序。还是没有例外。

有人可以告诉我一些可以产生连接重置异常的方法吗,以及工作示例代码。

java java-8 socketexception
5个回答
9
投票

以上答案在 Mac 和 Linux 上对我来说都不起作用。 经过大量谷歌搜索后,我以这篇文章结束了,解释了如何做到这一点。需要明确的是:我试图从客户端重现连接重置,即“对等方重置连接”。

我尝试启动一个运行 netcat 的进程,然后突然终止该进程 - 该进程仅适用于 Mac。

我从另一个线程尝试了socket.close,同一个线程 - 没有任何效果。

简单来说,所有这些方法都没有导致客户端向服务器发送 RST,从而导致异常(由对等方重置)。

以下方法有效:

  • 设置任何服务器 - 在我的例子中是 Netty(他们的入门丢弃服务器就可以了)。
  • 使用以下客户端代码:
final Socket socket = new Socket("localhost", port);;
socket.setSoLinger(true, 0);
final OutputStream outputStream = socket.getOutputStream();
for (int i=0; i <= 500; i++) {
    outputStream.write('a');
}
outputStream.write('\n');
outputStream.flush();
socket.close();

Thread.sleep(2000);

soLinger() 是一个魔术。根据上面引用的 Oracle 文章,当您调用 socket.close() 时,它会向另一端发送 RST,而不是发送 FIN,然后等待另一端完成读取发送的内容,直到 FIN - 即强制关闭.

我花了 1 天的时间才找到这个问题,所以我希望它能节省你的工作时间。


2
投票

有几种方法。我不会发布其中之一,因为它被滥用了,但制作它的简单方法是:

  1. 获取套接字后立即关闭它,而不读取任何内容。如果发件人是向您发送而不是从您那里读取,则此方法有效。
  2. 如果您知道发送者已发送了某些内容,请关闭套接字而不以任何方式读取它。

1
投票

这对我有用:

class Server {

    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(9999);
        Socket s = ss.accept();
        InputStream i = s.getInputStream();
        i.read();
    }
}

客户端连接和断开连接而不关闭套接字

class Client {

    public static void main(String[] args) throws Exception {
        Socket s = new Socket("localhost", 9999);
    }
}

这会导致服务器出现异常

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at net.Server.main(Server.java:13)

1
投票

通过将 soLinger 设置为 true 并在关闭连接之前等待一秒钟,我成功地重现了它:

导入java.io.IOException; 导入 java.net.ServerSocket; 导入java.net.Socket;

公共类 TCPServer { 公共静态无效主(字符串[] args){ 最终int PORT = 5500;

    try (ServerSocket serverSocket = new ServerSocket(PORT)) {
        System.out.println("Server listening on port " + PORT);

        while (true) {
            Socket clientSocket = serverSocket.accept();
            System.out.println("New client from " + clientSocket.getInetAddress() + ":" + clientSocket.getPort());
            Thread.sleep(1000); // Sleep for 1 second
            clientSocket.setSoLinger(true, 0);
            clientSocket.close();
        }

    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

} 在这篇文章中找到了这个解决方案:Troubleshooting java.netConnection Reset


-1
投票

我发现编写一个简短的 Python 脚本更容易,而不是使用 Java 客户端代码引发此异常:

import struct, socket
s = socket.socket(socket.AF_INET6)
s.connect(("::1", 8000))
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
s.close() # provokes Connection Reset at host
© www.soinside.com 2019 - 2024. All rights reserved.