我如何在GCDAsyncSocket中获得didReadData在当前RunLoop中执行



我试图得到一个简单的例子与GCDAsyncSocket工作,我发现我错过了某些理解,希望你好的人可以帮助解释这个。

我已经设置了GCDAsyncSocket下面的东西:

dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
NSString *host = @"192.168.169.132";
uint16_t port = 2112;
DDLogInfo(@"Connecting to "%@" on port %hu...", host, port);
self.viewController.label.text = @"Connecting...";
NSError *error = nil;
if (![asyncSocket connectToHost:host onPort:port withTimeout:5.0 error:&error])
{
    DDLogError(@"Error connecting: %@", error);
    self.viewController.label.text = @"Oops";
}
else
{
    DDLogVerbose(@"Connecting...");
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    DDLogInfo(@"socket:%p didConnectToHost:%@ port:%hu", sock, host, port);
    self.viewController.label.text = @"Connected";
    // We're just going to send a test string to the server.
    NSString *myStr = @"testing...123...rn";
    NSData *myData = [myStr dataUsingEncoding:NSUTF8StringEncoding];
    [asyncSocket writeData:myData withTimeout:5.0 tag:0];
}

可以看到我的套接字测试服务器应用程序接收字符串

"测试……123…… r n"

但是当我让套接字测试服务器返回一个字符串时,我天真地期望didReadData委托执行

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

然而冷酷无情的现实迫使我明白,直到我打电话给

[asyncSocket readDataWithTimeout:5.0 tag:0];

didReadData委托将不会被调用。

好的,很好。我明白了。

再仔细阅读一下文档它清楚地说明

AsyncSocket是一个基于RunLoop的TCP套接字库。

现在我在看这个RunLoop东西,在我看来就像Microsoft Windows中的Message循环。因为iOS是一个事件/msg驱动的架构(就像Win32一样),那么我目前所在的默认主线程显然有自己的msg循环来处理事件。

我的困惑是现在有iOS RunLoop似乎是一些独立的实体必须在获得GCDAsyncSocket工作正常。

当它声明它的运行循环模式的默认设置是nsdefaulunloopmode时,它在主线程中。

困惑了吗?

所以在Win32下,我的通信事件处理代码看起来像这样:

while( sCOMport.hCOMport != INVALID_HANDLE_VALUE )  // ...while the COM port is open...
{
    // Wait for an event to occur on the port.
    WaitCommEvent( sCOMport.hCOMport, &dwCommStatus, NULL );

它当然会在自己的线程中(还没有使用GCDAsyncSocket),但在某种程度上,这将是它自己的"RunLoop"。

我如何使用GCDAsyncSocket这样我就不会陷入一些轮询循环填充队列与[asyncSocket readDataWithTimeout]调用?

好了,我让它以某种方式工作了。

让我知道这是否违背了某些"最佳实践"。

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    // setup as normal...
    // then ...
    // Instigate the first read
    [asyncSocket readDataWithTimeout:-1 tag:0];
.
.
}

然后……当数据传入…

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    // Do whatever you need to do with the data ...
.
.
.
    // and at the end ...
.
.
    // Always keep a 'read' in the queue.
    [asyncSocket readDataWithTimeout:-1 tag:0];
}

这将为您提供RunLoop操作,而不使用计时器或其他结构。并且可以被包含在自己的线程中。

我知道这是一个老问题,已经有一个公认的答案,但这里是我的解决方案,我已经在我的一个应用程序中使用:

连接到主机后,运行以下调度队列:

dispatch_queue_t alwaysReadQueue = dispatch_queue_create("com.cocoaasyncsocket.alwaysReadQueue", NULL);
dispatch_async(alwaysReadQueue, ^{
    while(![socket isDisconnected]) {
        [NSThread sleepForTimeInterval:5];
        [socket readDataWithTimeout:-1 tag:0];
    }
});

您可以使用相同的队列来发送心跳请求,以保持连接存活。

相关内容

  • 没有找到相关文章

最新更新