objective-c 使用 NSStream 进行套接字编程

objective-c socket programming with NSStream

我创建了一个实现 NSStreamDelegate 的 MySocketClient class,并实现了方法 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

然后调用以下函数连接服务器:

- (void)connectToHost:(NSString *)host onPort:(UInt32)port{

NSLog(@"will connect...");
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);

_inputStream = (__bridge NSInputStream *)readStream;
_outputStream = (__bridge NSOutputStream *)writeStream;

_inputStream.delegate = self;
_inputStream.delegate = self;

[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[_inputStream open];
[_outputStream open];
}

很高兴连接我的服务器,但是委托方法:

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

未调用。

'connectToHost' 在 AppDelegate.m 文件的方法 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 中被调用,如下所示:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    GoEasySocketClient *client = [[GoEasySocketClient alloc] init];
    [client connectToHost:@"myhost" onPort:myport];
});

但奇怪的是,如果我使用 AppDelegate 作为 NSStreamDelegate,并实现方法 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

当我调用 connectToHost 方法时,委托方法 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode 将被调用,事件代码为 NSStreamEventOpenCompleted.

当您使用第二个线程时,您应该 运行 根据 apple documentation 您自己的 运行 循环。所以在你的情况下它应该如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    GoEasySocketClient *client = [[GoEasySocketClient alloc] init];
    [client connectToHost:@"myhost" onPort:myport];
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
});

或者您可以使用 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]] 而不是 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]。 唯一的区别是第一个“returns 在处理第一个输入源或达到 limitDate 之后”和 另一个“运行通过重复调用runMode:beforeDate作为NSDefaultRunLoopMode中的接收者:直到指定的到期日期”。

我用 NSURLConnection 试过第一个,效果很好。

你也可以使用主线程的运行循环。在这种情况下,您应该按如下方式更改代码:

[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

关于您的问题:

But the strange thing is if I use the AppDelegate as the NSStreamDelegate, and implement the method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode and when I call connectToHost method, the delegate method - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode will be called and the eventCode is NSStreamEventOpenCompleted.

发生这种情况是因为您使用自己的 运行 循环从主线程调用 connectToHost 方法。此 运行 循环会在应用程序启动期间自动启动。