使用通知实时从NSTask获取数据不起作用

时间:2012-01-20 17:57:49

标签: cocoa real-time nsnotifications nsnotificationcenter nstask

我有一个Cocoa命令行程序,我尝试运行NSTask程序(tshark来监控网络)并实时从中获取数据。所以我做了一个     NSFileHandle ,调用waitForDataInBackgroundAndNotify发送通知,然后将我的帮助类注册到通知中心以处理数据,但不会向我的帮助类发送单个通知。

有人知道可能出现什么问题吗?

提前致谢

这是我的代码:

#import <Foundation/Foundation.h>
#import <string>
#import <iostream>

@interface toff : NSObject {}
-(void) process:(NSNotification*)notification;
@end

@implementation toff
-(void) process:(NSNotification*)notification{
    printf("Packet caught!\n");
}
@end

int main (int argc, const char * argv[]){
    @autoreleasepool {
        NSTask* tshark = [[NSTask alloc] init];
        NSPipe* p = [NSPipe pipe];
        NSFileHandle* read = [p fileHandleForReading];
        toff* t1 = [[toff alloc] init];
        NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];

        [read waitForDataInBackgroundAndNotify];
        [nc addObserver:t1 selector:@selector(process:) name:nil object:nil];

        printf("Type 'stop' to stop monitoring network traffic.\n");
        [tshark setLaunchPath:@"/usr/local/bin/tshark"];
        [tshark setStandardOutput:p];
        [tshark launch];

        while(1){
            std::string buffer;
            getline(std::cin, buffer);
            if(buffer.empty()) continue;
            else if(buffer.compare("stop") == 0){
                [tshark interrupt];
                break;
            }
        }

        //NSData* dataRead = [read readDataToEndOfFile];
        //NSLog(@"Data: %@", dataRead);
        //NSString* stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];
        //NSLog(@"Output: %@", stringRead);

    }
    return 0;
}

编辑:当我取消注释已注释的代码段并删除所有通知内容时,所有需要的数据都会在任务完成后从文件句柄中提取。

我也想知道,如果问题不能实际上,我的程序是'命令行工具'所以我不确定它是否已经运行循环 - 正如Apple文档所说的那样(在NSFileHandle的waitForDataInBackgroundAndNotify消息中) :

  

您必须从具有活动运行循环的线程调用此方法。

3 个答案:

答案 0 :(得分:10)

自10.7以来有一个新API,因此您可以避免使用NSNotifications。

task.standardOutput = [NSPipe pipe];
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
    NSData *data = [file availableData]; // this will read to EOF, so call only once
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

    // if you're collecting the whole output of a task, you may store it on a property
    [self.taskOutput appendData:data];
}];

您可能希望对task.standardError重复上述内容。

重要:

当你的任务终止时,你必须将readabilityHandler块设置为nil;否则,您将遇到高CPU使用率,因为读数永远不会停止。

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

    [task.standardOutput fileHandleForReading].readabilityHandler = nil;
    [task.standardError fileHandleForReading].readabilityHandler = nil;
}];

这都是异步的(你应该做异步),所以你的方法应该有^完成块。

答案 1 :(得分:1)

启动任务后,程序立即完成。您需要将任务告诉wait until exit。这将运行run循环,等待子进程退出并巧合地启用文件句柄来监视管道。当任务退出时,该方法将返回,您可以继续执行main

答案 2 :(得分:0)

查看asynctask.m,示例代码,演示如何实现异步stdin,stdout&amp;使用NSTask处理数据的stderr流(虽然可能还有改进的余地)。