繁体   English   中英

通过TCP管理Java中的套接字连接

[英]manage socket connection in Java over tcp

我写了一个客户端,基本上只打开一个套接字并通过连接发送内容。 (内容遵循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();
                          }
           }

}

在此处输入图片说明

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

  • 服务器关闭了插座的一端,基本上是说我不再发送了
  • 您已经等待了一段时间,而又厌倦了等待并决定自己关闭插座。
  • 任何其他错误条件,但通常它们都看起来像接收0字节或负数。

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

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

对于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块代替:

解决了。

我现在了解它是如何工作的。 我在客户端中缺少的是尝试从输入Stream读取的内容。 当您尝试阅读时

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

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

之后,您可以安全地在客户端上关闭连接。 无需延迟FIN等

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM