【问题标题】:Disconnecting a socket to server断开与服务器的套接字
【发布时间】:2018-04-02 13:52:04
【问题描述】:

我正在尝试通过创建套接字并将其连接到服务器、发送消息并关闭套接字(通过服务器的 close 方法)来测试我的聊天客户端应用程序。但是,似乎当我关闭套接字时,客户端线程仍在等待客户端输入。但是,我已经放置了 if 子句来阻止它等待。这是我的测试:

   @Test
    public void testMessagesReceived() throws IOException
 {  
    ServerSocket s = server.getSocket();
    System.out.println(s);  
    mysocket = new Socket("127.0.0.1", 3000);

    final PrintWriter stream = new PrintWriter(mysocket.getOutputStream(), true);

    stream.println("Default room");

}
    @AfterSuite
public void stopServer() {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {  
        e.printStackTrace();
    }
    server.stop();
}

但是,当server.stop() 执行并关闭套接字时,我在客户端线程中遇到异常,该线程处于活动状态并使用此套接字,此处:

 public void acceptFromConsole() throws IOException {

    if (!socket.isClosed()) {


    final BufferedReader fromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    String message;
    while ((message = fromClient.readLine()) != null) { // Exception here
    if (message.contains(TelnetUtilities.Quit.toString())) {
        room.removeClient(id);
        break;
    }   
}

这是完整的堆栈跟踪:

   java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at com.egt.chat.server.ClientContainer.acceptFromConsole(ClientContainer.java:40)
at com.egt.chat.server.ClientContainerRunnable.run(ClientContainerRunnable.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

在我看来,在一个线程中我关闭了套接字,但是客户端线程没有看到套接字上的更改,并且检查 if(!socket.isClosed()) 返回 true 并且执行流程继续并且当我尝试读取它时,当然会抛出我试图从关闭的套接字读取的异常,有没有办法克服这个问题?

【问题讨论】:

  • 只是一个建议,如果您的目标是编写客户端-服务器应用程序,请尝试将您的代码清楚地划分为客户端和服务器。

标签: java sockets


【解决方案1】:

您的代码运行正常。当您强行断开套接字时,您的代码就是 while 循环:

  while ((message = fromClient.readLine()) != null) { // Exception here
      if (message.contains(TelnetUtilities.Quit.toString())) {
          room.removeClient(id);
          break;
      }

readLine() 正在等待传入数据。如果您不关闭连接,它将永远等待新数据。然后关闭连接,readLine()(或更好的底层socketRead 方法)现在认识到它无法从关闭的套接字读取数据并引发异常。

因此,此时此异常是预期的异常。抓住它并快乐起来。

我会这样做:添加一个布尔变量,如 stopServerCalled,默认情况下为 false,并在调用 stopServer() 时设置为 true

try {
    while ((message = fromClient.readLine()) != null) { // Exception here
        if (message.contains(TelnetUtilities.Quit.toString())) {
            room.removeClient(id);
            break;
        }
} catch (SocketException e) {
    // check if this is an expected exception and if yes ignore it
    if (!stopServerCalled) 
        throw e;
}

【讨论】:

  • 谢谢它有效,但我也尝试将 if 子句从 !socket.isClosed() 更改为 !socket.isConnected 并且它有效,为什么?
  • 然后您可以完全删除 if 子句,因为当抛出 SocketException 时,套接字始终未连接... if 子句的目的是确定中断是由您的代码故意引起的还是可能是网络错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 2014-12-02
相关资源
最近更新 更多