如何阻止Java Socket客户端不断发送“空”数据?

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

提问人:Evan Gunawan 提问时间:2/2/2019 更新时间:2/3/2019 访问量:1864

问:

我创建了 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();
    }
}

我试图关闭客户端的 OutputStream,但它在发送 0-4 循环后将 null 发送到服务器。 为了使它停止并避免客户端发送 null 数据,我不应该在客户端上插入 ,但它将返回 SocketException。我希望客户端在完成后发送“已关闭”消息。clientOutput.close();serverSock.close();

摘要,服务器上的输出为:

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

我认为客户端程序中缺少一些东西,我猜? 感谢您的帮助:)

Java 套接字 服务器 IOSTREAM

评论

1赞 user207421 2/3/2019
它不会发送“null”数据。请参阅 Javadoc 了解 。readLime()

答:

-2赞 mehdi maick 2/2/2019 #1

通常,代码应该是类似的

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!");
}

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

评论

0赞 user207421 2/3/2019
循环是正确的,但不需要终止消息。对等体只需关闭套接字将导致此循环退出。readLine()
0赞 mehdi maick 2/3/2019
是的,我知道,但您可能需要它来改善客户端和服务器之间的通信
0赞 user207421 2/3/2019
如何改进它?
-1赞 Mohammed Anas AR 2/3/2019 #2

你的 MainClient() 没有问题。

MainServer() 中的 clientSocket.isConnected() 函数始终检查客户端的状态并导致无限循环,因此在消息 'client:4' 之后,clientInput.readLine() 应返回 'null'。

因此,您可以使用函数“clientSocket.isClosed()”来检查客户端套接字是否已连接,而不是检查客户端套接字是否已连接。

将 MainServer() 中的 while 循环替换为以下代码,

       while(!clientSocket.isClosed()) {

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

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

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

评论

1赞 user207421 2/3/2019
isConnected()在服务器中从不检查客户端的状态。 此处既不检测客户端关闭,也不检测“帮助您关闭客户端套接字”。它在这里没有比 更好的工作了。显然你从未尝试过。isClosed()isConnected()
2赞 President James K. Polk 2/3/2019 #3

正如注释所指出的,客户端没有发送值。null

该方法不会做你认为它所做的事情,即它不会告诉你套接字当前是否“连接”到它的对等体,至少以你认为它应该的方式。 一旦套接字转换到连接状态,就会变为 true,此后即使套接字关闭后,它也会保持 true。请参阅此讨论和 stackoverflow 上的其他讨论。isConnected()isConnected()

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

返回值:
一个 String 包含该行的内容,不包括 任何行终止字符,如果流的末尾具有 已达到
Throws:
IOException - 如果发生 I/O 错误

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

评论

0赞 Evan Gunawan 2/4/2019
明白了。谢谢你的解释。那么,使用下面解释的答案这样的条件来确定对等体是否已关闭/关闭连接更好?clientInput.readLine()!=null
1赞 user207421 2/4/2019
@motionfrog这正是他已经说过的。这不仅仅是“更好”,它是唯一有效的选择。