Java 套接字和断开的连接
检测套接字是否被丢弃的最合适方法是什么?或者数据包是否真的被发送了?
我有一个库,用于通过Apple gatways(可在GitHub上找到)将Apple Push通知发送到iPhone。客户端需要打开一个套接字并发送每条消息的二进制表示形式;但不幸的是,苹果没有返回任何确认。该连接也可以重复用于发送多条消息。我正在使用简单的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);
在某些情况下,如果在发送消息时或之前断开连接; 不过,成功完成。我预计这是由于TCP窗口尚未耗尽。Socket.getOutputStream().write()
有没有办法确定数据包是否真的进入了网络?我尝试了以下两种解决方案:
插入具有 250 毫秒超时的附加操作。这将强制读取操作在断开连接时失败,否则将挂起 250 毫秒。
socket.getInputStream().read()
将 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