检测套接字是否被丢弃的最合适的方法是什么?或者一个数据包是否真的被发送了?
我有一个库,用于通过 Apple 网关(在 GitHub 上可用)向 iPhone 发送 Apple 推送通知。客户端需要打开一个套接字并发送每条消息的二进制表示;但不幸的是,Apple 没有返回任何确认。该连接也可以重复用于发送多条消息。我正在使用简单的 Java Socket 连接。相关代码为:
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 窗口尚未耗尽。
有没有办法可以确定一个数据包是否真的进入了网络?我尝试了以下两种解决方案:
socket.getInputStream().read()
插入具有 250 毫秒超时的附加操作。这会强制执行在连接断开时失败的读取操作,否则会挂起 250 毫秒。将 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");
}
[顺便说一句,我还有一个并发测试库,它使设置更好更清晰。也可以在 gist 处查看示例]。
运行时,我得到以下输出:
Closed socket
writing new packets
Finished writing
Run without any errors