【问题标题】:manage socket connection in Java over tcp通过 tcp 在 Java 中管理套接字连接
【发布时间】:2015-05-26 16:10:34
【问题描述】:

我编写了一个客户端,它基本上只是打开一个套接字并通过连接发送内容。 (内容遵循Http协议)

我面临的问题是关于这个问题 - 我应该如何以及何时关闭连接。 问题是连接有时过早关闭(“FIN”在服务器应答之前发送到服务器)。

在这种情况下,服务器的答案丢失了。
我尝试在关闭连接之前使用 Thread.sleep ,但似乎没有什么影响发送内容和发送“FIN”消息之间的时间。 (在 Wireshark 中查看)

答案有时会到达,有时不会(竞争条件)。

如何延迟“FIN”消息,以免错过服务器的响应?

我添加了相关的类。相关函数是sendContentOverSocket

public class SocketClient {

           private String hostName;
           private int portNumber;
           private Socket ConnectionSocket;

           public void init(String hostName, int portNumber){
                          this.hostName = hostName;
                          this.portNumber = portNumber;
                          this.ConnectionSocket=createSocketConnection();

           }

           private Socket createSocketConnection() {
                          Socket socket = null;
                          try {
                                         socket = new Socket(this.hostName, this.portNumber);
                                         return socket;
                          } catch (UnknownHostException e) {
                                         e.printStackTrace();
                          } catch (IOException e) {
                                         e.printStackTrace();
                          }

                          return socket;
           }

           public void sendContentOverSocket(String content) {
                          try {
                                         PrintWriter out = new PrintWriter(
                                                                       ConnectionSocket.getOutputStream(), true);
                                         BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                       ConnectionSocket.getInputStream()));
                                         out.print(content);

                                         try {
                                                        Thread.sleep(2000);
                                         } catch (InterruptedException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                         }

                                         out.close();
                                         in.close();                           
                                         ConnectionSocket.close();

                          } catch (IOException e) {
                                         e.printStackTrace();
                          }
           }

}

【问题讨论】:

  • @user1274820 除非您做错了什么,否则套接字不会“因错误而关闭”。

标签: java sockets tcp tcpclient


【解决方案1】:

TCP 使用一个称为半关闭的概念。 当您关闭套接字时,表明您将不再发送。 在您的解释中,我看到“在服务器应答之前将 FIN 发送到服务器”,如果您是客户端,这意味着您已经对套接字执行了关闭操作。 如果您希望在某个时间范围内从服务器获得结果,则需要某种计时机制,可能将 select 与超时结合使用。 如果服务器关闭了他的连接端,您可以通过在接收中接收字节来检测这一点。通常这意味着您也必须关闭套接字。 因此,总而言之,您关闭套接字的原因有 3 个:

  • 服务器关闭他的套接字,基本上说我不再发送了
  • 你已经等了一段时间,你已经厌倦了等待,决定自己关闭套接字。
  • 任何其他错误情况,但通常它们都显示为接收 0 字节或负数。

【讨论】:

  • 谢谢,但我如何“等待一段时间”?我在发送消息后和关闭连接之前尝试使用睡眠,但它没有按预期工作。您可以在 wireshark 图像中看到睡眠(出于某种原因)在 Http 之前执行,而不是在发送 FIN 之前。
  • 你应该使用 select api。您确实使用套接字上的读取集进行选择并指定超时时间为 10 秒。如果数据在套接字上可用或发生超时,则 Select 将返回。如果是超时,则关闭套接字。
  • 或者更确切地说,因为这是Socket,,所以您使用setSoTimeout() 设置读取超时并捕获结果。 SocketTimeoutException.
【解决方案2】:

当然,您应该在阅读响应后关闭连接。很难看出这里的奥秘。没有睡觉。如果您不阅读响应(a)您无法知道请求是成功还是失败,并且(b)服务器也有可能遇到异常。

您的代码质量很差。所有这些方法都应该传播异常,而不是在内部捕获它们并返回 null。

【讨论】:

  • 这只是问题的一个简单示例。异常处理得到照顾。谢谢。
【解决方案3】:

在 Java 7 的情况下,由于所有三个类,即SocketPrintWriterBufferedReader,都实现了AutoCloseable,并且基于事实,您希望在调用sendContentOverSocket(String content) 后立即关闭套接字尝试使用以下代码:

    public class SocketClient {

    private String hostName;
    private int portNumber;

    public void init(String hostName, int portNumber) {
        this.hostName = hostName;
        this.portNumber = portNumber;
    }

    public void sendContentOverSocket(String content) {
        try (Socket socket = new Socket(this.hostName, this.portNumber);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            out.print(content);
        } catch(IOException e) {
            //Appropriate exception handler
        }
    }
}

在这种情况下,Java 会自行正确关闭所有资源。

如果您使用 Java 6 或更早版本,请尝试改用 try-finally 块:

【讨论】:

    【解决方案4】:

    解决了。

    我现在明白它是如何工作的了。 我在客户端中缺少的是尝试从输入流中读取。 当你尝试阅读时

    while ((inputFromServer = in.readLine()) != null)
    

    客户端等待输入。唯一会打破这个循环的是服务器关闭连接。

    之后,您可以安全地关闭客户端的连接。不需要延迟FIN之类的......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多