Java套接字编程:尽管关闭套接字,连接重置?

时间:2018-03-30 14:48:26

标签: java sockets tcp

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

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

Server.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?
    }

Client.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终端发出命令),一切正常.Page

我仍然是套接字编程的新手,所以我也可能有一个逻辑缺陷。任何帮助将非常感谢,因为我真的想继续这个项目。 提前致谢!

1 个答案:

答案 0 :(得分:3)

此异常的原因是您在连接服务器后终止了客户端,但服务器仍然从流中读取内容。发生异常。这是我测试的代码:

    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循环中的条件以检查输入流是否仍可供读取。