सॉकेट को गिरा दिया गया है या नहीं, यह पता लगाने का सबसे उचित तरीका क्या है? या क्या वास्तव में एक पैकेट भेजा गया था?जावा सॉकेट और ड्रॉप किए गए कनेक्शन
मेरे पास ऐप्पल गेटवे (available on GitHub) के माध्यम से iPhones में ऐप्पल पुश अधिसूचनाएं भेजने के लिए एक लाइब्रेरी है। ग्राहकों को सॉकेट खोलने और प्रत्येक संदेश का बाइनरी प्रतिनिधित्व भेजने की आवश्यकता होती है; लेकिन दुर्भाग्य से ऐप्पल किसी भी पावती को वापस नहीं लौटाता है। कई संदेशों को भेजने के लिए कनेक्शन का पुन: उपयोग किया जा सकता है। मैं सरल जावा सॉकेट कनेक्शन का उपयोग कर रहा हूँ। प्रासंगिक कोड है:
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()
हालांकि सफलतापूर्वक समाप्त होता है। मुझे उम्मीद है कि टीसीपी विंडो अभी तक समाप्त नहीं हुई है।
क्या कोई तरीका है कि मैं यह सुनिश्चित करने के लिए कह सकता हूं कि वास्तव में नेटवर्क में एक पैकेट मिला है या नहीं? मैं निम्नलिखित दो समाधान के साथ प्रयोग:
एक 250ms समय समाप्ति के साथ एक अतिरिक्त
socket.getInputStream().read()
आपरेशन डालें। यह एक पठन ऑपरेशन को मजबूर करता है जो कनेक्शन को छोड़ने में विफल रहता है, लेकिन अन्यथा 250ms के लिए लटकता है।संदेश बाइनरी आकार में टीसीपी भेजने बफर आकार (उदा।
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");
}
[संयोग से, मैं भी एक संगामिति परीक्षण पुस्तकालय, सेटअप करता है कि एक सा बेहतर और स्पष्ट है: यहाँ मुख्य विधि है। गिस्ट पर भी नमूना चेकआउट करें]।
जब चलाने मैं निम्नलिखित उत्पादन प्राप्त करें:
अद्यतन उत्तर। –
जैसा कि मैंने पहले ही अपने उत्तर में कहा है, यदि आप यह सुनिश्चित करना चाहते हैं कि कोई त्रुटि नहीं है तो आपको एक सुंदर कनेक्शन समाप्ति करना होगा। शटडाउन आउटपुट() को निष्पादित करें, तब तक जब तक आप ईओएफ प्राप्त नहीं करते हैं, तब सॉकेट बंद करें। सुप्रसिद्ध कनेक्शन समाप्ति संक्षेप में सहकर्मी से एक स्वीकृति प्राप्त करने में है कि यह आपको ठीक है, जो वही है जो आप चाहते हैं। –