2013-10-12 6 views
7

मैं एनएसएसट्रीम का उपयोग करके चैट एप्लिकेशन बना रहा हूं जो एक साधारण सी सॉकेट सर्वर से कनेक्ट होता है। स्ट्रीम सफलतापूर्वक कनेक्ट हो जाती है, और डेटा भेजती है, लेकिन यह डेटा प्राप्त करने में असमर्थ है।एनएसएसटी स्ट्रीम डेटा प्राप्त करने में विफल

Socket.h

@interface Socket : NSObject <NSStreamDelegate> 

- (void)connectToServerWithIP:(NSString *)ip andPort:(int)port; 
- (NSString *)sendMessage:(NSString *)outgoingMessage; 

@end 

Socket.m

#import "Socket.h" 

@interface Socket() 

@property (strong, nonatomic) NSInputStream *inputStream; 
@property (strong, nonatomic) NSOutputStream *outputStream; 
@property (strong, nonatomic) NSString *output; 

@end 

@implementation Socket 

@synthesize inputStream; 
@synthesize outputStream; 
@synthesize output; 

- (void)connectToServerWithIP:(NSString *)ip andPort:(int)port 
{ 
    CFReadStreamRef readStream; 
    CFWriteStreamRef writeStream; 
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)ip, port, &readStream, &writeStream); 
    inputStream = (__bridge_transfer NSInputStream *)readStream; 
    outputStream = (__bridge_transfer NSOutputStream *)writeStream; 
    [inputStream setDelegate:self]; 
    [outputStream setDelegate:self]; 
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [inputStream open]; 
    [outputStream open]; 
} 

- (NSString *)sendMessage:(NSString *)outgoingMessage 
{ 
    NSData *messageData = [outgoingMessage dataUsingEncoding:NSUTF8StringEncoding]; 
    const void *bytes = [messageData bytes]; 
    uint8_t *uint8_t_message = (uint8_t*)bytes; 
    [outputStream write:uint8_t_message maxLength:strlen([outgoingMessage cStringUsingEncoding:[NSString defaultCStringEncoding]])]; 
    while (![inputStream hasBytesAvailable]) { 
     usleep(10); 
    } 
    uint8_t buffer[1024]; 
    [inputStream read:buffer maxLength:1023]; 
    NSString *outputString = [NSString stringWithUTF8String:(char *)buffer]; 
    return outputString; 
} 

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent { 
    NSLog(@"Stream Event: %lu", streamEvent); 

    switch (streamEvent) { 
     case NSStreamEventOpenCompleted: 
      NSLog(@"Stream opened"); 
      break; 
     case NSStreamEventHasBytesAvailable: 
      if (theStream == inputStream) { 
       uint8_t buffer[1024]; 
       long len; 
       while ([inputStream hasBytesAvailable]) { 
        len = [inputStream read:buffer maxLength:sizeof(buffer)]; 
        if (len > 0) { 
         output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding]; 
         if (output) { 
          NSLog(@"Data: %@", output); 
         } 
        } 
       } 
      } 
      break; 
     case NSStreamEventErrorOccurred: 
      NSLog(@"Can not connect to the host!"); 
      break; 
     case NSStreamEventEndEncountered: 
      [theStream close]; 
      [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      theStream = nil; 
      break; 
     default: 
      NSLog(@"Unknown event"); 
    } 
} 

@end 

ChatViewController.m

// 
// ChatViewController.m 
// Chat 
// 
// Created by James Pickering on 10/5/13. 
// Copyright (c) 2013 James Pickering. All rights reserved. 
// 

#import "ChatViewController.h" 
#import "LoginViewController.h" 
#import "StatusView.h" 

@interface ChatViewController() 

@property (strong) IBOutlet NSTableView *people; 
@property (strong) IBOutlet NSTextField *message; 
@property (strong) IBOutlet NSButton *send; 
@property (strong) IBOutlet NSButton *loginButton; 
@property (strong) IBOutlet NSButton *settingsButton; 
@property (strong) IBOutlet NSButton *panicButton; 

@property (strong, nonatomic) NSString *recievedText; 
@property (strong, nonatomic) NSMutableArray *tableData; 
@property (strong, nonatomic) NSInputStream *inputStream; 
@property (strong, nonatomic) NSOutputStream *outputStream; 


- (void)openChat:(id)sender; 

- (IBAction)panic:(id)sender; 
- (IBAction)loginToChat:(id)sender; 

@end 

@implementation ChatViewController 

@synthesize sock; 
@synthesize recievedText; 
@synthesize inputStream; 
@synthesize outputStream; 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     self.isLoggedIn = FALSE; 
     sock = [[Socket alloc] init]; 
     [sock connectToServerWithIP:@"127.0.0.1" andPort:5001]; 
     //[self updateUI]; 
    } 
    return self; 
} 

- (void)updateUI 
{ 
    if (self.isLoggedIn) { 
     recievedText = [sock sendMessage:@"getPeople"]; 
     self.tableData = [[NSMutableArray alloc] initWithArray:[recievedText componentsSeparatedByString:@";"]]; 
     NSLog(@"%@", self.tableData); 
     [self.people reloadData]; 
    } 
} 

- (void)openChat:(id)sender 
{ 
    NSLog(@"tru"); 
} 

- (IBAction)panic:(id)sender { 

} 

- (IBAction)loginToChat:(id)sender { 
    NSLog(@"Called"); 
    if (self.loginPopover == nil) { 
     NSLog(@"Login Popover is nil"); 
     self.loginPopover = [[NSPopover alloc] init]; 
     self.loginPopover.contentViewController = [[LoginViewController alloc] initWithNibName:@"LoginViewController" bundle:nil]; 
    } 
    if (!self.loginPopover.isShown) { 
     NSLog(@"Login Popover is opening"); 
     [self.loginButton setTitle:@"Cancel"]; 
     [self.settingsButton setEnabled:NO]; 
     [self.send setEnabled:NO]; 
     [self.message setEnabled:NO]; 
     [self.loginPopover showRelativeToRect:self.loginButton.frame ofView:self.view preferredEdge:NSMinYEdge]; 
    } 
    else { 
     NSLog(@"Login Popover is closing"); 
     [self.loginButton setTitle:@"Login"]; 
     [self.settingsButton setEnabled:YES]; 
     [self.send setEnabled:YES]; 
     [self.message setEnabled:YES]; 
     [self.loginPopover close]; 
    } 
} 

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView 
{ 
    return [self.tableData count]; 
} 

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex 
{ 
    return [self.tableData objectAtIndex:rowIndex]; 
} 

- (BOOL)canBecomeKeyWindow 
{ 
    return YES; 
} 

- (BOOL)loginWithUsername:(NSString *)username andPassword:(NSString *)password 
{ 
    // Error happens here 

    recievedText = [sock sendMessage:@"login"]; 
    if ([recievedText isEqualToString:@"roger"]) { 
     recievedText = [sock sendMessage:[NSString stringWithFormat:@"%@;%@", username, password]]; 
     if ([recievedText isEqualToString:@"access granted"]) { 
      return YES; 
     } 
     else { 
      return NO; 
     } 
    } 
    else { 
     return NO; 
    } 
} 

@end 

समस्या यह है कि इस पर लटकी हुई है: यहाँ मेरी सॉकेट वर्ग NSStreams का उपयोग करता है कोड की यह एक पंक्ति हमेशा के लिए: while (![inputStream hasBytesAvailable]) {}, लेकिन मुझे नहीं पता कि क्यों। सर्वर को एक संदेश वापस भेजना चाहिए।

+0

मुझे एक ही समस्या का सामना करना पड़ रहा है ... कोई समाधान? –

उत्तर

4

तो, अपने NSStreamDelegate पर ध्यान दें, ऐसा लगता है कि आपने उस स्विच स्टेटमेंट के सभी मामलों को लागू नहीं किया है। मैंने हाल ही में ओएस एक्स के लिए एक आईआरसी क्लाइंट लिखा है जो NSStream और NSStreamDelegate का उपयोग इसी तरह से करता है, और मुझे पूरा यकीन है कि संकलक को तब शिकायत करनी चाहिए जब आपने वहां सभी मामलों की जांच नहीं की हो।

some of my code यह लग रहा है आप मामलों

  • NSStreamEventHasSpaceAvailable
  • NSStreamEventOpenCompleted
  • NSStreamEventHasBytesAvailable
  • NSStreamEventEndEncountered
  • NSStreamEventErrorOccurred
के लिए जाँच की जानी चाहिए की तरह करने के लिए वापस देख रहे हैं

तो जिस मामले में आपने चेक नहीं किया है वह NSStreamEventHasSpaceAvailable है, जो तब होता है जब आप अपनी स्ट्रीम में लिखना शुरू कर सकते हैं।

संपादित करें: अपने कोड को फिर से पढ़ना, मैं अपने sendMessage कार्रवाई में है कि आप outputStream वस्तु का उपयोग कर रहे बजाय प्रतिनिधि के लिखने के लिए, और फिर काम खुद inputStream से पढ़ने के लिए कर रही है देखते हैं। मुझे लगता है कि आप शायद प्रतिनिधि का उपयोग करना चाहते हैं और सीधे अपने इनपुटस्ट्रीम से कभी नहीं पढ़ना चाहते हैं क्योंकि यह आपके कोड को नेटवर्क से डेटा प्राप्त करने के तरीके को बहुत सरल बना देगा। जो मैं समझता हूं, NSStream इस तथ्य के आस-पास अमूर्तता की एक छोटी परत प्रदान करने के लिए है कि डेटा को नेटवर्क से बफर किया गया है, इसलिए आपको usleep पर कॉल करने की आवश्यकता नहीं है, जबकि आपके इनपुटस्ट्रीम में पढ़ने के लिए बाइट्स उपलब्ध नहीं हैं।

संपादित 2: मैंने आपके कोड के बारे में अपना अपडेट कभी भी while (![inputStream hasBytesAvailable]) प्राप्त नहीं किया है और यह स्पष्ट है कि समस्या यह है कि आप अपनी स्ट्रीम का सही उपयोग नहीं कर रहे हैं। जिस तरह से मैं इसे देखता हूं, NSStream का उपयोग करने का सबसे अच्छा तरीका है handleEvent:(NSStreamEvent) event विधि का उपयोग करके घटनाओं का जवाब देना, और बाइट्स लिखने के लिए इसे सीधे बताएं, या जब तक बाइट उपलब्ध न हो जाएं तब तक सोएं।

कोड में मैंने जो लिंक किया है, मेरे पास एक पढ़ा गया है और एक लिखने वाला है जो दोनों NSStreams को संभालते हैं, तो आप शायद यह देखना चाहें कि मैं अपने लेखन का उपयोग कैसे करता हूं here। मेरे पास मूल रूप से एक विधि है, addCommand:(NSString *) command जो स्ट्रीम को कतार में लिखने के लिए एक स्ट्रिंग रखता है, और फिर जब मेरा स्ट्रीम प्रतिनिधि बाइट्स (NSStreamEventHasSpaceAvailable) लिख सकता है, तो मैं जितना कर सकता हूं उतने बाइट लिख सकता हूं। आशा है कि ये आपकी मदद करेगा!

+0

जवाब देने के लिए धन्यवाद। मेरे पास इनपुट स्ट्रीम करने का कारण यह है क्योंकि मैं नहीं चाहता कि अगर कोई बाइट उपलब्ध न हो तो मैं शून्य वापस लौटना चाहूंगा, इसलिए जब तक कि इसमें कुछ वापस न हो जाए तब तक मैं लूप करता हूं। मजाकिया बात यह है कि जब मैं कोड से 'if (isLoggedIn)' लाइन लेता हूं, तो अद्यतन यूआई में कोड डेटा भेजने और प्राप्त करने के लिए पूरी तरह से काम करता है। मैं आपके सुझाव में देख रहा हूं और मुझे उम्मीद है कि यह काम करता है। – jamespick

+0

'NSStreamEventHasSpaceAvailable' के बजाय 'NSStreamHasSpaceAvailable' कुछ भी नहीं है। –

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