2013-03-20 10 views
14

मैं ऑब्जेक्टिव-सी के लिए SocketRocket लाइब्रेरी का उपयोग का उपयोग कर बंद करने नहीं है:WebSocket कनेक्शन एक WebSocket से कनेक्ट करने के SocketRocket

-(void)open { 

if(self.webSocket) { 
    [self.webSocket close]; 
    self.webSocket.delegate = nil; 
} 

self.webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://192.168.0.254:5864"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20]]; 
self.webSocket.delegate = self; 
[self.webSocket open]; 
} 

कनेक्शन खुलने का पूरी तरह से ठीक काम करता है। कनेक्शन स्थापित होने के बाद प्रतिनिधि को बुलाया जाता है।

-(void)webSocketDidOpen:(SRWebSocket *)webSocket { 

NSLog(@"WebSocket is open"); 

} 

लेकिन जब मैं कनेक्शन बंद करना चाहता हूं, तो कुछ भी नहीं होता है।

-(void)close { 

if(!self.webSocket) 
    return; 

[self.webSocket close]; 
self.webSocket.delegate = nil; 

} 

कनेक्शन को सफलतापूर्वक बंद करने के लिए प्रतिनिधि को नहीं कहा जाता है। क्या कोई मुझे बता सकता है कि ऐसा क्यों होता है?

मेरा प्रश्न पढ़ने के लिए धन्यवाद।

+0

यह स्थिति क्या है "अगर (! Self.webSocket)"? –

+0

इसका मतलब है कि वेबस्केट को बंद होने पर बंद नहीं किया जा सकता है, क्योंकि तब यह –

+0

नहीं खोलता है, मुझे हमेशा यह त्रुटि मिल रही है और भाषण में टेस्ट ऑडियो अवरोध प्राप्त कर रहा है, WebSocket कारण के साथ बंद [1000]: सॉकेट को मैन्युअल रूप से समाप्त करना कनेक्शन कोई सुझाव? –

उत्तर

4

मुझे पता चला कि प्रतिनिधि को कभी नहीं कहा जाता है, क्योंकि वेबसाईट कभी भी बंद नहीं होता है। SRWebSocket में WebSocket के समापन इस तरह विधि pumpWriting में क्या होता है:

if (_closeWhenFinishedWriting && 
    _outputBuffer.length - _outputBufferOffset == 0 && 
    (_inputStream.streamStatus != NSStreamStatusNotOpen && 
    _inputStream.streamStatus != NSStreamStatusClosed) && 
    !_sentClose) { 
    _sentClose = YES; 

    [_outputStream close]; 
    [_inputStream close]; 

    if (!_failed) { 
     dispatch_async(_callbackQueue, ^{ 
      if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) { 
       [self.delegate webSocket:self didCloseWithCode:_closeCode reason:_closeReason wasClean:YES]; 
      } 
     }); 
    } 

    _selfRetain = nil; 

    NSLog(@" Is really closed and released "); 
} 
else { 

    NSLog(@" Is NOT closed and released "); 
} 

सभी नदियों और एक वस्तु WebSocket बनाए रखने के लिए बंद कर दिया या वहाँ नष्ट हो जाती हैं। जब तक वे अभी भी खुले हैं, सॉकेट उचित रूप से बंद नहीं किया जाएगा। लेकिन मेरे कार्यक्रम में समापन कभी नहीं हुआ, क्योंकि जब मैंने वेबसाईट बंद करने की कोशिश की, _closeWhenFinishedWriting हमेशा नहीं था।

यह बूलियन केवल डिस्कनेक्ट विधि में सेट हो गया है।

- (void)_disconnect; 
{ 

assert(dispatch_get_current_queue() == _workQueue); 
SRFastLog(@"Trying to disconnect"); 
_closeWhenFinishedWriting = YES; 
[self _pumpWriting]; 

} 

लेकिन जब SRWebSocket में closeWithCode विधि, डिस्कनेक्ट केवल एक मामले में कहा जाता है और है कि, अगर WebSocket जोड़ने राज्य में है बुला।

BOOL wasConnecting = self.readyState == SR_CONNECTING; 

SRFastLog(@"Closing with code %d reason %@", code, reason); 
dispatch_async(_workQueue, ^{ 

    if (wasConnecting) { 
     [self _disconnect]; 
     return; 
    } 

इसका मतलब है, अगर सॉकेट किसी अन्य राज्य में है, तो वेबस्केट कभी भी बंद नहीं होगा। एक कामकाज हमेशा डिस्कनेक्ट विधि को कॉल करना है। कम से कम यह मेरे लिए काम किया और सब कुछ ठीक लगता है।

अगर किसी के पास कोई विचार है, तो क्यों SRWebSocket को इस तरह लागू किया गया है, कृपया इस उत्तर के लिए एक टिप्पणी छोड़ दें और मेरी मदद करें।

+0

मुझे SRWebSocket –

+0

के पूरे कोड में कहीं भी डिस्कनेक्ट विधि नहीं मिल रही है मुझे हमेशा यह त्रुटि मिल रही है और ऑडियो बाधा प्राप्त करने के लिए भाषण परीक्षण, वेबसाकेट कारण से बंद [1000]: सॉकेट कनेक्शन को मैन्युअल रूप से समाप्त करना कोई सुझाव? –

4

मुझे लगता है कि यह एक बग है।
बंद होने पर, सर्वर गूंज 'बंद' संदेश वापस ले जाता है।
यह SRWebSocket द्वारा प्राप्त किया जाता है, हालांकि _selfRetain कभी भी शून्य पर सेट नहीं होता है, और सॉकेट खुला रहता है (धाराएं बंद नहीं होती हैं) और हमारे पास स्मृति रिसाव है।
मैंने परीक्षण चैट ऐप में भी इसे चेक और देखा है।

-(BOOL)_innerPumpScanner {  
    BOOL didWork = NO; 

    if (self.readyState >= SR_CLOSING) { 
     [self _disconnect]; // <--- Added call to disconnect which releases _selfRetain 
     return didWork; 
    } 

अब सॉकेट बंद कर देता है, उदाहरण के जारी किया गया है, और स्मृति रिसाव चला गया है:
मैं निम्नलिखित परिवर्तन किया है।
एकमात्र चीज जो मुझे यकीन नहीं है वह है अगर इस तरह से बंद होने पर प्रतिनिधि को बुलाया जाना चाहिए। इसमें देखेंगे।

+0

हाँ आप सही हैं। जैसा कि मैंने अपने उत्तर में बताया है, _Disconnect को BOOL _closeWhenFinishedWriting को YES पर सेट करने के लिए बुलाया जाना चाहिए, ताकि _selfRetain को उचित रूप से –

+0

सही पर सेट किया जा सके। ऐसा कोई मामला है जब कोई सर्वर मर जाता है, प्रतिनिधि को अधिसूचित नहीं किया जाएगा, और बस वहां बैठेगा। मैंने परिवर्तन किए हैं इसलिए प्रतिनिधि को अधिसूचित किया जाता है। मैंने एक [पुल अनुरोध] बनाया है (https://github.com/square/SocketRocket/pull/106) यदि कोई भी मेरे द्वारा किए गए परिवर्तन देखना चाहता है। – emp

+0

इस मुद्दे को गिटहब पर पता चला है, हालांकि फिक्स को विलय नहीं किया गया है। https://github.com/mediumbear/SocketRocket/commit/08afedbeb991edfda13aa675b5720c53ffaf7ef8 –

2

एक बार एक endpoint दोनों भेजा है और एक बंद नियंत्रण फ्रेम प्राप्त हुआ है, कि endpoint WebSocket कनेक्शन के रूप में धारा 7.1.1 में परिभाषित बंद हो जाना चाहिए। (RFC 6455 7.1.2)

SRWebSocket उदाहरण नहीं _disconnect यहाँ क्योंकि उस सर्वर से पहले ग्राहक के जवाब में एक बंद नियंत्रण फ्रेम करने के लिए प्राप्त हुआ है TCP कनेक्शन बंद कर करता है। वास्तव में, _disconnect आईएनजी टीसीपी सॉकेट को फाड़ देगा इससे पहले कि क्लाइंट सर्वर पर अपना खुद का फ्रेम फ्रेम भी भेज सके, क्योंकि _disconnect से पहले _pumpWriting पर कॉल कर सकता है। सर्वर शायद पर्याप्त रूप से पर्याप्त प्रतिक्रिया देगा, लेकिन यह गैर-अनुरूप है, और आप इस तरह से चीजों को स्थापित करते समय स्थिति-अद्वितीय बंद कोड भेजने में सक्षम नहीं होंगे।

यह ठीक से साथ handleCloseWithData:

if (self.readyState == SR_OPEN) { 
    [self closeWithCode:1000 reason:nil]; 
} 
dispatch_async(_workQueue, ^{ 
    [self _disconnect]; 
}); 

में यह ब्लॉक बंद दोनों क्लाइंट और सर्वर द्वारा शुरू अनुरोधों को प्रबंधित की जाती है। यदि सर्वर पहला बंद फ्रेम भेजता है, तो विधि आपके द्वारा निर्धारित अनुक्रम के अनुसार चलती है, अंततः में closeWithCode: के माध्यम से समाप्त हो जाती है, जहां ग्राहक अपने स्वयं के बंद फ्रेम के साथ जवाब देगा। फिर यह _disconnect के साथ कनेक्शन को फाड़ने के लिए चला जाता है।

जब ग्राहक पहले फ्रेम भेजता है, तो closeWithCode: एक बार टीसीपी कनेक्शन बंद किए बिना चलाता है क्योंकि _closeWhenFinishedWriting अभी भी झूठा है। इस सर्वर समय अपने स्वयं के बंद फ्रेम, जो आम तौर पर closeWithCode: फिर से चलाने में परिणाम होगा साथ प्रतिक्रिया करने के लिए अनुमति देता है, लेकिन यह है कि विधि के शीर्ष पर निम्नलिखित ब्लॉक के लिए:

if (self.readyState == SR_CLOSING || self.readyState == SR_CLOSED) { 
    return; 
} 

readyState पहले यात्रा पर बदल गया है क्योंकि closeWithCode: का, इस बार यह आसानी से नहीं चलेगा।

इस काम को इरादे के रूप में बनाने के लिए एएमपी का बग फिक्स आवश्यक है, अन्यथा: सर्वर से बंद फ्रेम कुछ भी नहीं करता है। कनेक्शन अभी भी समाप्त हो जाएगा, लेकिन गंदे रूप से, क्योंकि सर्वर (दोनों ने अपने फ्रेम भेजे और प्राप्त किए हैं) सॉकेट को अपने अंत में तोड़ देंगे, और ग्राहक NSStreamEventEndEncountered: के साथ प्रतिक्रिया देगा, जो आम तौर पर अचानक नुकसान के कारण स्ट्रीम त्रुटियों के लिए आरक्षित होता है कनेक्टिविटी की। एक बेहतर तरीका यह निर्धारित करना होगा कि फ्रेम कभी भी _innerPumpScanner से handleCloseWIthData: से क्यों नहीं निकलता है। ध्यान में रखने के लिए एक और मुद्दा यह है कि डिफ़ॉल्ट रूप से, close केवल आरएफसी-गैर-अनुरूप कोड -1 के साथ closeWithCode: पर कॉल करता है। इसने मेरे सर्वर पर त्रुटियों को फेंक दिया जब तक कि मैंने इसे स्वीकार किए गए मानों में से एक भेजने के लिए नहीं बदला।

सभी ने कहा कि: आपकी प्रतिनिधि विधि काम नहीं करती है क्योंकि आप close पर कॉल करने के बाद प्रतिनिधि को सही तरीके से परेशान कर रहे हैं। close में सब कुछ एक एसिंक ब्लॉक के अंदर है; जब आप didCloseWithCode: का आह्वान करते हैं, तब तक कॉल करने के लिए एक प्रतिनिधि नहीं छोड़ा जाएगा, चाहे आप यहां और क्या करें।

+0

मुझे हमेशा यह त्रुटि मिल रही है और भाषण में टेस्ट ऑडियो अवरोध प्राप्त कर रहा है, वेबसाकेट कारण से बंद [1000]: सॉकेट कनेक्शन को मैन्युअल रूप से समाप्त करना कोई सुझाव? –

संबंधित मुद्दे