代码之家  ›  专栏  ›  技术社区  ›  DaedricNight

Java套接字编程:关闭套接字后连接重置?

  •  1
  • DaedricNight  · 技术社区  · 6 年前

    我目前正在编写一个简单的TCP聊天客户端服务器应用程序,它可以与套接字一起工作。客户端连接到服务器,一旦被接受,就会创建一个新的工作线程来侦听客户端输入。连接到服务器(端口8818处的本地主机)工作正常,但只要工作线程在登录后开始侦听更多客户端输入 a java.net.SocketException: Connection reset 抛出(请参见下面的堆栈跟踪)。我知道,此异常的一个可能来源可能是服务器或客户端未正确或强制关闭的套接字。因此,我的假设是,我没有正确处理关闭客户端套接字的操作,这会导致连接重置。

    我想要实现的目标: 工作者侦听客户端输入,只要该输入不为null,就会处理请求(例如简单登录),否则,套接字将关闭(请参阅下面的代码摘录)。我的客户端从服务器收到一条“登录成功”消息,指示我的 handleLogin() 函数可以工作,但在没有收到来自客户端的更多输入后,服务器似乎只是重置,而不是关闭套接字,即使 clientSocket.close() 在while循环之后发出。

    服务器Java语言

    @Override
        public void run() {
    
            try {
    
                ServerSocket serverSocket = new ServerSocket(serverPort);
    
                while (true) {
    
                    // Accept connection(s) from new chat client(s)
                    System.out.println("SERVER: WAITING TO ACCEPT CLIENT CONNECTIONS ...");
                    Socket clientSocket = serverSocket.accept();
                    System.out.println("SERVER: CONNECTION ACCEPTED FROM: " + clientSocket);
                    // Process client request in separate Thread
                    WorkerThread worker = new WorkerThread(this, clientSocket);
                    workerList.add(worker);
                    worker.start();
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    WorkerThread。Java语言

     @Override
        public void run() {
    
            try {
                handleClientSocket();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
    
        private void handleLogin(OutputStream outputStream, String[] tokens) throws IOException {
    
            if (tokens.length != 3) {
                outputStream.write("LOGIN FAILED!\n".getBytes());
                    return;
            }
    
            // Extract username and password from user input
            String username = tokens[1];
            String password = tokens[2];
    
            if (username.equals("anna") && password.equals("anna")) {
    
                outputStream.write("Login successful!\n".getBytes());
    
            } else {
                outputStream.write("Error logging in!\n".getBytes());
            }
    
        }
    
        private void handleClientSocket() throws IOException, InterruptedException {
    
            InputStream inputStream = clientSocket.getInputStream();
            this.outputStream = clientSocket.getOutputStream();
    
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
    
            // THIS IS WHERE THE EXCEPTION OCCURS AFTER CLIENT HAS LOGGED IN SUCCESSFULLY
            while ((line = bufferedReader.readLine()) != null) {
    
                String[] tokens = StringUtils.split(line);
    
                if (tokens.length > 0 && tokens != null) {
    
                    String command = tokens[0];
    
                    // Evaluate the entered command and handle the request accordingly
    
                    if ("login".equalsIgnoreCase(command)) {
                        handleLogin(outputStream, tokens);
                    } 
    
                    // process other commands ...  
    
                }
            }
    
            clientSocket.close();   // POSSIBLY WORNG WAY OF CLOSING THE CLIENT SOCKET?
        }
    

    客户Java语言

    import java.io.*;
    import java.net.Socket;
    
    public class Client {
    
        private final String serverName;
        private final int serverPort;
        private Socket mySocket;
        private OutputStream serverOut;
        private InputStream serverIn;
    
        public Client(String serverName, int serverPort) {
            this.serverName = serverName;
            this.serverPort = serverPort;
        }
    
        private boolean connect() {
    
            try {
                mySocket = new Socket(serverName, serverPort);
                serverOut = mySocket.getOutputStream();
                serverIn = mySocket.getInputStream();
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        private void login(String username, String password) throws IOException {
            String command = "login " + username + " " + password + "\n";
            serverOut.write(command.getBytes());
        }
    
        public static void main(String[] args) throws IOException {
    
            Client client = new Client("localhost", 8818);
    
            if (client.connect()) {                             
                System.out.println("Connection successful!");   
                client.login("anna", "anna");                   
    
            } else {
                System.err.println("Connection failed ...");
            }
    
        }
    
    }
    

    堆栈跟踪

    java.net.SocketException: Connection reset
        at java.net.SocketInputStream.read(SocketInputStream.java:189)
        at java.net.SocketInputStream.read(SocketInputStream.java:121)
        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 WorkerThread.handleClientSocket(WorkerThread.java:70)
        at WorkerThread.run(WorkerThread.java:45)
    

    当我用PUTTY测试我的服务器时(即通过连接到localhost,然后在PUTTY的终端中发出命令),一切正常。

    我对socket编程还是相当陌生的,所以这里可能也有一个逻辑缺陷。任何帮助都将非常感谢,因为我真的很想继续这个项目。 提前感谢!

    1 回复  |  直到 6 年前
        1
  •  3
  •   YCXU1993    6 年前

    出现此异常的原因是,您在连接服务器后终止了客户端,但服务器仍从流中读取某些内容。出现异常。下面是我测试的代码:

        while (inputStream.available() != 0) {
            line = bufferedReader.readLine();
            String[] tokens = StringUtils.split(line);
    
            if (tokens.length > 0 && tokens != null) {
    
                String command = tokens[0];
    
                // Evaluate the entered command and handle the request accordingly
    
                if ("login".equalsIgnoreCase(command)) {
                    handleLogin(outputStream, tokens);
                } 
    
                // process other commands ...  
    
            }
        }
    

    更改while循环中的条件,以检查inputstream是否仍然可以读取。