使用通知从 NSTask 实时获取数据不起作用
我有一个 Cocoa 命令行程序,在其中尝试运行 NSTask 程序(使用 tshark 来监视网络)并从中实时获取数据。所以我做了一个 NS文件句柄 ,调用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;
}
编辑:当我取消注释代码的注释部分并删除所有通知内容时,任务完成后将从文件句柄中提取所有所需的数据。
我还想知道,如果问题实际上不可能是我的程序是“命令行工具”,所以我不确定它是否有运行循环 - 正如苹果文档所说需要的(在 NSFileHandle 的 waitForDataInBackgroundAndNotify 消息中):
您必须从具有活动运行循环的线程调用此方法。
I got a Cocoa command-line program in which I try to run NSTask
program (tshark
to monitor network) and get data from it in real-time. So I make a
NSFileHandle
, call waitForDataInBackgroundAndNotify
to send notifications and then register my help class to Notification center to process the data, but not a single notification is sent to my help class.
Does anybody have an idea of what could be wrong?
Thanks in advance
Here is my code:
#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;
}
EDIT: When I uncomment commented section of code and delete all that notification stuff, all desired data are extracted from file handle after task finish.
I was also wondering, if problem can't be in fact, that my program is 'Command line tool' so I am not sure if it has run loop - as Apple documentation says is needed (in waitForDataInBackgroundAndNotify message of NSFileHandle):
You must call this method from a thread that has an active run loop.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从 10.7 开始有一个新的 API,因此您可以避免使用 NSNotifications。
也许您想对
task.standardError
重复上面的操作。重要提示:
当你的任务终止时,你必须将 readabilityHandler 块设置为 nil;否则,你会遇到高 CPU 使用率,因为读取永远不会停止。
这都是异步的(并且您应该异步执行),因此您的方法应该有一个 ^completion 块。
There's a new API since 10.7, so you can avoid using NSNotifications.
Probably you want to repeat the same above for
task.standardError
.IMPORTANT:
When your task terminates, you have to set readabilityHandler block to nil; otherwise, you'll encounter high CPU usage, as the reading will never stop.
This is all asynchronous (and you should do it async), so your method should have a ^completion block.
您的程序在启动任务后立即完成。您需要将任务告诉 等待退出。这将运行运行循环,等待子进程退出并同时启用文件句柄来监视管道。当任务退出时,该方法将返回,您可以继续到
main
的末尾。Your program finishes immediately after launching the task. You need to tell the task to wait until exit. That will run the run loop, waiting for the child process to exit and coincidentally enabling the file handle to monitor the pipe. When the task does exit, the method will return and you can proceed to the end of
main
.看一下 asynctask.m,示例代码展示了如何实现异步 stdin、stdout &用于使用 NSTask 处理数据的 stderr 流(不过可能还有改进的空间)。
Have a look at asynctask.m, sample code that shows how to implement asynchronous stdin, stdout & stderr streams for processing data with NSTask (there may be room for improvement though).