gpt4 book ai didi

Java 套接字和丢弃的连接

转载 作者:搜寻专家 更新时间:2023-10-30 19:54:51 25 4
gpt4 key购买 nike

检测套接字是否已被丢弃的最合适方法是什么?或者数据包是否真的被发送了?

我有一个库,用于通过 Apple 网关 (available on GitHub) 向 iPhone 发送 Apple 推送通知。客户端需要打开一个套接字并发送每条消息的二进制表示;但不幸的是,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() 操作,超时为 250 毫秒。这会强制执行读取操作,该操作在连接断开时失败,否则会挂起 250 毫秒。

  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

关于Java 套接字和丢弃的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2028620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com