如何停止 Java Socket 客户端不断发送 'null' 数据?

How to stop Java Socket client keeps sending 'null' data?

我创建了 2 个 Java 带有套接字的程序。我希望客户端向服务器发送连续数据。但是在消息发送到服务器之后,客户端继续向服务器发送 'null' 值(当我关闭客户端程序中的套接字时发生)。 这是我的代码:

import ...
public class MainClient {
    private Socket serverSock;
    private PrintStream clientOutput;

    public static void main(String[] args) {
        MainClient client = new MainClient();
        client.runClient();
    }
    public void runClient() {
        try {
            serverSock = new Socket("127.0.0.1",8282);
            clientOutput = new PrintStream(serverSock.getOutputStream());
            clientOutput.println("Hello, I'm Connected.");

            for (int i=0;i<5;i++) {
                clientOutput.println(i + "");
                clientOutput.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
//          try {
//              serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
//          } catch (IOException e) {
//              e.printStackTrace();
//          }
        }
    }
}

服务器端:

public class MainServer {

    private ServerSocket serverSocket;
    private int listenPort = 8282;
    private InputStream inps;
    private Socket clientSocket;
    private BufferedReader clientInput;

    private MainServer() {
        String clientMsg = "";
        try {
            serverSocket = new ServerSocket(listenPort);
            System.out.println("Server is Listening on " + listenPort);
            clientSocket = serverSocket.accept();
            clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            while(clientSocket.isConnected()) {
                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);                
            }
        }catch(IOException ex) {
            ex.printStackTrace();
        }finally {
            try {
                clientSocket.close();
            } catch (IOException e) {}
        }
    }
    public static void main(String[] args) {
        new MainServer();
    }
}

我尝试使用 clientOutput.close(); 关闭客户端的 OutputStream,但它在发送 0-4 循环后将空值发送到服务器。 为了让它停止并避免客户端发送空数据,我不应该在客户端上插入 serverSock.close();,但它会 returns SocketException。我希望客户端在完成后发送 'Closed' 消息。

总结,服务器上的输出是:

Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..

我想客户端程序缺少某些东西,我猜? 谢谢你的帮助:)

通常代码应该类似于

private MainServer() {
  String clientMsg = "";
  try {
    serverSocket = new ServerSocket(listenPort);
    System.out.println("Server is Listening on " + listenPort);
    clientSocket = serverSocket.accept();
    clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    while ((clientMsg = clientInput.readLine()) != null) {
      if(isTerminationString(clientMsg)) { 
        break;
      }
      System.out.println("Client : " + clientMsg);
    }
  } catch (IOException ex) {
    ex.printStackTrace();
  } finally {
    try {
      clientSocket.close();
    } catch (IOException e) {
    }
  }
}

boolean isTerminationString(String msg) {
  return msg.equals("DONE!");
}

isTerminationString 你检查消息是否是终止消息的地方,通信协议应该在客户端和服务器之间共享。我举了发送的例子 DONE 消息,但它可能比那更复杂。 由于关闭套接字上的 close 方法并不能保证另一部分的套接字也被关闭,因此使用 isClosed 方法可能无效并导致与您遇到的相同问题。

你的MainClient()没有问题。

MainServer() 中的

clientSocket.isConnected() 函数总是检查客户端的状态,这会导致无限循环,因此在消息 'client:4' 之后,clientInput.readLine() 应该 return 'null'.

因此,您可以使用函数 'clientSocket.isClosed()'.

检查客户端套接字是否已关闭,而不是检查客户端套接字是否已连接

用下面的代码替换 MainServer() 中的 while 循环,

       while(!clientSocket.isClosed()) {

                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);

                if(clientMsg.equals("Closed")){
                     clientSocket.close();
                //  serverSocket.close();
                }
            }

这将帮助您在从服务器接收到 'Closed' 消息时关闭客户端套接字,从而避免无限执行 while 循环以及打印 null 语句。 代码 "serverSocket.close()" 帮助您关闭服务器套接字,如果您需要停止端口监听,您可以在 'MainServer()' 处使用它。

如评论所述,客户端未发送 null 值。

isConnected() 方法并没有像您想象的那样做,即它 没有 告诉您套接字当前是否 "connected" 到它的对等方,至少以您认为应该的方式。 isConnected() 在套接字转换为连接状态后立即变为真,此后保持真,即使在套接字关闭后也是如此。在 Whosebug 上查看 this discussion 和其他人。

确定对等方是否已关闭连接的正确方法是尝试从套接字读取,然后检查结果以寻找关闭的证据。请阅读您正在使用的方法的 Javadocs,它们会告诉您各种 return 值的含义。对于 BufferedReader.readLine() 方法,它表示:

Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Throws:
IOException - If an I/O error occurs

因此您需要检查空 return 值以检测正常的套接字关闭,以及是否收到指示某种网络异常的 IOException。