7

У меня есть программа командной строки Cocoa, в которой я пытаюсь запустить программу NSTask (tshark10 для мониторинга сети) и получать данные из нее в режиме реального времени. Поэтому я делаю NSFileHandle , звоните waitForDataInBackgroundAndNotify, чтобы отправлять уведомления, а затем зарегистрировать мой класс справки в Центре уведомлений для обработки данных, но ни одно уведомление не отправляется в мой класс справки.Получение данных из NSTask в режиме реального времени с использованием уведомлений не работает

Есть ли у кого-нибудь представление о том, что может быть неправильным?

Заранее спасибо

Вот мой код:

#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: Когда я раскомментировать прокомментировал раздел кода и удалить все, что уведомление вещи, все нужные данные извлекаются из дескриптора файла после завершение задачи.

Мне также интересно, если проблема не может быть на самом деле, что моя программа «Инструмент командной строки», поэтому я не уверен, что она запускает цикл - по мере того, как требуется документация Apple (в сообщении waitForDataInBackgroundAndNotify от NSFileHandle):

Вы должны вызвать этот метод из потока, который имеет активный цикл цикла.

+0

Вы действительно должны сделать это 'addObserver: selector: name: object:' message более конкретным. Вы в настоящее время подписываетесь на * любое * уведомление, а не только на уведомление NSFileHandleReadCompletionNotification. –

+0

Цикл выполнения неявно создается при необходимости, поэтому вы можете смело предположить, что «он имеет [цикл] запуска», но вам нужно его запустить. Приложение будет запускать цикл цикла для вас, поэтому все, что вам нужно сделать, это вернуть, но в инструменте командной строки вы должны запустить цикл выполнения самостоятельно. Я рекомендую использовать NSFileHandle для чтения со стандартного ввода, а также делать то, что я сказал в своем ответе, чтобы запустить цикл выполнения, пока задача не завершится. –

+0

@PeterHosey Хорошая идея - спасибо. Я пытался это сделать, но не работал. Поэтому я отступил к простой, опустившейся остановке и придумал [это] (http://pastebin.com/qnhaUAjp) (я также заметил, что данные, переданные 'NSFileHandle', как-то буферизованы - не знают, как избавиться из этого) После запуска он ждет некоторое время, а затем пишет «Пакет пойман» один раз - тогда ничего. Если я раскомментирую 1, то он ждет, а затем напишет «Пакет поймал» неограниченное количество раз. И наконец, когда я пытаюсь извлечь данные и раскомментировать _2 -5_ он ждет некоторое время, пишет строки _2 & 3_, а затем зависает. Не сбой, никаких ошибок, просто не извлекайте данные. – user1023979

ответ

1

Ваша программа заканчивается сразу после запуска задачи. Вам нужно сообщить задание wait until exit. Это запустит цикл выполнения, ожидая выхода дочернего процесса и совпадения, позволяя дескриптору файла контролировать канал. Когда задача завершается, метод вернется, и вы можете перейти к концу main.

+0

Я должен опубликовать весь код. Я отредактировал свой ответ - теперь вы можете видеть, что я предоставляю пользователю возможность вручную остановить задачу из моей программы. Я думаю, что если бы я назвал 'waitUntilExit', это было бы невозможно. Я также попытался извлечь данные из обработчика файла после остановки задачи (комментарий), и он отлично работал. – user1023979

+0

И когда я говорю «Я отредактировал свой ответ», я имею в виду «я отредактировал мой вопрос» - извините – user1023979

0

Посмотрите на asynctask.m, пример кода, который показывает, как реализовать асинхронный stdin, stdout & потоки stderr для обработки данных с помощью NSTask (возможно, там может быть место для улучшения).

8

Существует новый API с 10.7, поэтому вы можете избежать использования 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 блок к нулю; в противном случае вы столкнетесь с высоким уровнем использования ЦП, поскольку чтение никогда не прекратится.

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

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

Это все асинхронный (и вы должны сделать это асинхронным), так что ваш метод должен иметь блок с^завершающим.