Cách thích hợp nhất để phát hiện xem ổ cắm có bị rơi hay không? Hoặc liệu một gói thực sự đã được gửi chưa?Ổ cắm Java và các kết nối bị rơi
Tôi có thư viện để gửi Thông báo đẩy của Apple tới iPhone thông qua các con đường của Apple (available on GitHub). Khách hàng cần phải mở một ổ cắm và gửi một đại diện nhị phân của mỗi tin nhắn; nhưng tiếc là Apple không trả lại bất kỳ sự thừa nhận nào. Kết nối có thể được tái sử dụng để gửi nhiều tin nhắn. Tôi đang sử dụng các kết nối Socket Java đơn giản. Mã có liên quan là:
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);
Trong một số trường hợp, nếu kết nối bị bỏ khi thư được gửi hoặc ngay trước đó; Socket.getOutputStream().write()
hoàn tất thành công. Tôi hy vọng đó là do cửa sổ TCP chưa hết.
Có cách nào để tôi có thể biết chắc liệu một gói thực sự có trong mạng hay không? Tôi đã thử nghiệm với hai giải pháp sau:
Chèn thêm
socket.getInputStream().read()
hoạt động với thời gian chờ 250ms. Điều này buộc một hoạt động đọc thất bại khi kết nối bị ngắt, nhưng bị treo khác 250ms.đặt kích thước bộ đệm gửi TCP (ví dụ:
Socket.setSendBufferSize()
) thành kích thước nhị phân thư.
Cả hai phương pháp đều hoạt động, nhưng chúng làm giảm đáng kể chất lượng dịch vụ; thông lượng đi từ 100 tin nhắn/giây đến khoảng 10 tin nhắn/giây nhiều nhất.
Mọi đề xuất?
CẬP NHẬT:
Thử thách bằng nhiều câu hỏi đặt câu hỏi về khả năng mô tả. Tôi đã xây dựng các bài kiểm tra "unit" của hành vi mà tôi mô tả. Xem các trường hợp đơn vị tại Gist 273786.
Cả hai bài kiểm tra đơn vị có hai luồng, một máy chủ và một máy khách. Máy chủ đóng trong khi máy khách đang gửi dữ liệu mà không có bất kỳ lỗi IOException nào được ném ra. Đây là phương pháp chính:
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");
}
[Ngẫu nhiên, tôi cũng có thư viện kiểm tra đồng thời, giúp thiết lập tốt hơn và rõ hơn một chút. Kiểm tra mẫu tại gist là tốt].
Khi chạy tôi nhận được kết quả như sau:
Câu trả lời được cập nhật. –
Như tôi đã nêu trong câu trả lời của tôi, nếu bạn muốn chắc chắn không có lỗi, bạn phải thực hiện một kết nối kết nối duyên dáng. Thực hiện shutdownOutput(), sau đó đọc cho đến khi bạn nhận được EOF, sau đó đóng socket. Kết thúc kết nối duyên dáng trong bản chất nhận được xác nhận từ người ngang hàng rằng nó đã nhận được bạn OK, đó chính là điều bạn muốn. –