当前位置: 首页 > 面试题库 >

Java套接字和断开的连接

汝飞
2023-03-14
问题内容

检测插座是否已掉落的最合适方法是什么?还是实际上是否发送过数据包?

我有一个库,用于通过Apple网关(在GitHub上提供)将Apple
Push Notifications发送到iPhone
。客户端需要打开一个套接字并发送每个消息的二进制表示形式。但不幸的是,Apple不会返回任何确认。该连接也可以重用于发送多个消息。我正在使用简单的Java套接字连接。相关代码为:

Socket socket = socket();   // returns an reused open socket, or a new one
socket.getOutputStream().write(m.marshall());
socket.getOutputStream().flush();
logger.debug("Message \"{}\" sent", m);

在某些情况下,如果在发送消息时或之前发送消息时断开了连接;Socket.getOutputStream().write()虽然成功完成。我希望这是由于TCP窗口尚未耗尽。

有什么方法可以确定一个数据包是否确实进入了网络?我尝试了以下两种解决方案:

  1. 插入socket.getInputStream().read()一个250ms超时的附加操作。这将导致读取操作在断开连接后失败,但会挂起250ms。

  2. 将TCP发送缓冲区大小(例如Socket.setSendBufferSize())设置为消息二进制大小。

两种方法都可以使用,但是会大大降低服务质量。吞吐率从100条消息/秒增加到最多10条消息/秒。

有什么建议?

更新:

质疑多个答案质疑所描述的可能性。我针对所描述的行为构建了“单元”测试。在Gist
273786处检查单元箱。

这两个单元测试都有两个线程,一个服务器和一个客户端。客户端发送数据时服务器关闭,而没有抛出IOException异常。这是主要方法:

public static void main(String[] args) throws Throwable {
    final int PORT = 8005;
    final int FIRST_BUF_SIZE = 5;

    final Throwable[] errors = new Throwable[1];
    final Semaphore serverClosing = new Semaphore(0);
    final Semaphore messageFlushed = new Semaphore(0);

    class ServerThread extends Thread {
        public void run() {
            try {
                ServerSocket ssocket = new ServerSocket(PORT);
                Socket socket = ssocket.accept();
                InputStream s = socket.getInputStream();
                s.read(new byte[FIRST_BUF_SIZE]);

                messageFlushed.acquire();

                socket.close();
                ssocket.close();
                System.out.println("Closed socket");

                serverClosing.release();
            } catch (Throwable e) {
                errors[0] = e;
            }
        }
    }

    class ClientThread extends Thread {
        public void run() {
            try {
                Socket socket = new Socket("localhost", PORT);
                OutputStream st = socket.getOutputStream();
                st.write(new byte[FIRST_BUF_SIZE]);
                st.flush();

                messageFlushed.release();
                serverClosing.acquire(1);

                System.out.println("writing new packets");

                // sending more packets while server already
                // closed connection
                st.write(32);
                st.flush();
                st.close();

                System.out.println("Sent");
            } catch (Throwable e) {
                errors[0] = e;
            }
        }
    }

    Thread thread1 = new ServerThread();
    Thread thread2 = new ClientThread();

    thread1.start();
    thread2.start();

    thread1.join();
    thread2.join();

    if (errors[0] != null)
        throw errors[0];
    System.out.println("Run without any errors");
}

[顺便说一句,我也有一个并发测试库,它使设置更好,更清晰。同样在要点检查样本]。

运行时,我得到以下输出:

Closed socket
writing new packets
Finished writing
Run without any errors

问题答案:

这对您没有太大帮助,但是从技术上讲,您提出的两个解决方案都不正确。OutputStream.flush()以及您可以想到的任何其他API调用都不会做您需要的事情。

确定对等方是否已接收到数据包的唯一可移植且可靠的方法是等待对等方的确认。该确认可以是实际响应,也可以是正常的套接字关闭。故事的结尾-
确实没有其他方法,而且这不是Java特定的-这是基本的网络编程。

如果这不是持久连接-也就是说,如果您只是发送一些东西然后关闭连接-
这样做的方式是捕获所有IOExceptions(它们中的任何一个都指示错误),然后执行正常的套接字关闭:

1. socket.shutdownOutput();
2. wait for inputStream.read() to return -1, indicating the peer has also shutdown its socket


 类似资料:
  • 问题内容: 大家好。我有一个使用ServerSocket和Socket类用Java编写的服务器。 我希望能够检测并处理断开连接,然后在必要时重新连接新客户端。 检测客户端断开连接,关闭套接字然后接受新客户端的正确步骤是什么? 问题答案: 大概是在从套接字读取数据,也许是在输入流上使用包装器,例如BufferedReader。在这种情况下,当相应的读取操作返回-1(对于原始read()调用)或为nu

  • 我想检查一下我的客户是否断开了连接。根据我的研究,一种可能的方式是我可以继续给客户写信。如果客户端未能接收到消息,则表示已断开连接。我向相应的客户端发送消息“Checking Connection:Client”clientNo。 我将clientNo 1连接到服务器,它接收 客户1 但是当我将另一个客户端连接到服务器时,我的clientNo1停止接收来自服务器的消息,我的clientNo2现在将

  • 问题内容: 我正在使用OpenShift和WildFly 8.2.1 final来实现新的HTML5 websocket。我使用了本教程来设置这个项目。 每当我打开MyTest.html时,这就是JavaScript记录的内容: 服务器连接,然后立即断开连接。为什么?我究竟做错了什么?有什么我想念的吗? 这是模式代码-> serverendpoint.java MyTest.html: 和pom.

  • 这很好,但没有SSL。 我已经使用OpenSSL为服务器和客户机生成了SSL证书,结果是: 服务器的证书(PEM格式) 客户端的证书(PEM格式) 服务器的私钥(PEM格式) 客户端的私钥(PEM格式) CA文件(PEM、CER和CRT格式) null 会出什么问题?

  • 线程“main”java.net.ConnectException:连接超时:在java.net.dualStackplainsockeTimpl.Connect0(本机方法)在java.net.dualStackplainsockeTimpl.socketConnect(DualStackplainsockeTimpl.java:69)在java.net.abstractplainsockeTi

  • 服务器名设置为“localhost”,端口为80。使用这些参数,我可以运行程序而没有任何异常,但是当代码到达in.readutf()行时,它会旋转。 当端口更改为任何其他端口时,我会得到一个连接拒绝异常。 另一方面,当我创建一个简单的“ServerSocket”程序接收端口80上的请求时,我会得到“Address Academy in use”异常,除了80之外的任何端口都适用于“ServerSo