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 方法。此 运行 循环会在应用程序启动期间自动启动。
我创建了一个实现 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 方法。此 运行 循环会在应用程序启动期间自动启动。