檢測套接字是否被丟棄的最合適的方法是什麼?或者一個數據包是否確實發送了?Java套接字和丟棄的連接
我有一個庫,用於通過Apple gatways向iPhone發送Apple推送通知(available on GitHub)。客戶需要打開一個套接字併發送每條消息的二進制表示;但不幸的是,蘋果公司並沒有回覆任何承認。該連接也可以重複使用以發送多條消息。我正在使用簡單的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()
操作,其中250ms超時。這會強制在連接斷開時失敗的讀取操作,但在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上也檢出樣品]。
在運行時我得到以下輸出:
已更新的答案。 – 2010-01-11 01:11:23
正如我在我的回答中所述,如果您想確保沒有錯誤,您必須執行正常的連接終止。執行shutdownOutput(),然後讀取,直到您收到EOF,然後關閉套接字。 優雅的連接終止本質上是從對等方接收到確認,它收到你確定,這正是你想要的。 – 2010-01-11 04:06:08