7

Tôi có chương trình dòng lệnh Cocoa, trong đó tôi cố gắng chạy chương trình NSTask (tshark để theo dõi mạng) và nhận dữ liệu từ đó trong thời gian thực. Vì vậy, tôi tạo NSFileHandle , gọi waitForDataInBackgroundAndNotify để gửi thông báo và sau đó đăng ký lớp trợ giúp của tôi cho Trung tâm thông báo để xử lý dữ liệu, nhưng không một thông báo nào được gửi đến lớp trợ giúp của tôi.Lấy dữ liệu từ NSTask trong thời gian thực bằng cách sử dụng thông báo không hoạt động

Có ai có ý tưởng về điều gì có thể sai không?

Cảm ơn trước

Đây là mã của tôi:

#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: Khi tôi bỏ ghi chú nhận xét phần của mã và xóa tất cả những thứ thông báo, tất cả các dữ liệu mong muốn được chiết xuất từ ​​tập tin xử lý sau hoàn thành nhiệm vụ. Tôi cũng tự hỏi, nếu vấn đề không thể là trên thực tế, chương trình của tôi là 'công cụ dòng lệnh' vì vậy tôi không chắc liệu nó có chạy vòng lặp hay không - như tài liệu Apple nói là cần thiết (trong waitForDataInBackgroundAndNotify thông điệp của NSFileHandle):

Bạn phải gọi phương thức này từ chuỗi có vòng chạy đang hoạt động.

+0

Bạn thực sự nên thực hiện 'addObserver: selector: name: object:' thông điệp cụ thể hơn. Bạn hiện đang đăng ký thông báo * any *, không chỉ thông báo 'NSFileHandleReadCompletionNotification'. –

+0

Vòng lặp chạy được tạo ra ngầm khi cần thiết, vì vậy bạn có thể giả định một cách an toàn “nó có [a] vòng lặp chạy”, nhưng bạn cần chạy nó. Một ứng dụng sẽ chạy vòng lặp chạy cho bạn, vì vậy tất cả những gì bạn cần làm là trả về, nhưng trong một công cụ dòng lệnh, bạn phải chạy vòng lặp chạy. Tôi khuyên bạn nên sử dụng NSFileHandle để đọc từ đầu vào tiêu chuẩn là tốt, và làm những gì tôi đã nói trong câu trả lời của tôi để chạy vòng lặp chạy cho đến khi nhiệm vụ thoát. –

+0

@PeterHosey Ý tưởng hay - thanks.I đã cố gắng làm điều này nhưng không hiệu quả. Vì vậy, tôi bước trở lại đơn giản, bỏ qua dừng lại và đến với [this] (http://pastebin.com/qnhaUAjp) (Tôi cũng nhận thấy rằng dữ liệu được thông qua bởi 'NSFileHandle' là bằng cách nào đó đệm - không biết làm thế nào để thoát khỏi của nó) Sau khi bắt đầu, nó chờ đợi một lúc và sau đó viết 'Packet caught' một lần - sau đó không có gì. Nếu tôi uncomment 1 thì nó chờ đợi và sau đó viết 'Packet caught' không giới hạn thời gian.Và cuối cùng khi tôi cố gắng trích xuất dữ liệu và uncomment _2 -5_ nó chờ đợi một thời gian, viết dòng _2 & 3_ và sau đó freezes.No tai nạn, không có lỗi, chỉ cần không trích xuất dữ liệu. – user1023979

Trả lời

1

Chương trình của bạn hoàn tất ngay sau khi khởi chạy tác vụ. Bạn cần phải thông báo cho công việc wait until exit. Điều đó sẽ chạy vòng lặp chạy, chờ đợi cho quá trình con để thoát ra và tình cờ cho phép xử lý tệp để theo dõi đường ống. Khi tác vụ thoát, phương thức sẽ trở lại và bạn có thể tiếp tục đến cuối main.

+0

Tôi nên đăng toàn bộ mã. Tôi đã chỉnh sửa câu trả lời của tôi - bây giờ bạn có thể thấy, rằng tôi đang cung cấp cho người dùng khả năng tự dừng nhiệm vụ từ chương trình của tôi. Tôi nghĩ rằng nếu tôi gọi 'waitUntilExit' thì điều đó sẽ không thể thực hiện được. Tôi cũng đã cố gắng trích xuất dữ liệu từ trình xử lý tệp sau khi dừng tác vụ (phần nhận xét) và nó hoạt động hoàn hảo. – user1023979

+0

Và khi tôi nói 'Tôi đã chỉnh sửa câu trả lời' Tôi có nghĩa là 'Tôi đã chỉnh sửa câu hỏi của mình' - xin lỗi – user1023979

0

Hãy xem asynctask.m, mã mẫu cho biết cách triển khai stdin không đồng bộ, stdout & luồng stderr để xử lý dữ liệu với NSTask (có thể có chỗ để cải thiện).

8

Có API mới từ 10.7, vì vậy bạn có thể tránh sử dụng 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]; 
}]; 

Có thể bạn muốn lặp lại tương tự ở trên cho task.standardError.

QUAN TRỌNG:

Khi tác vụ của bạn chấm dứt, bạn phải đặt khả năng đọcBộ chặn khối để không; nếu không, bạn sẽ gặp phải mức sử dụng CPU cao, vì việc đọc sẽ không bao giờ dừng lại.

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

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

Đây là tất cả không đồng bộ (và bạn nên làm không đồng bộ), vì vậy phương pháp của bạn phải có khối hoàn thành ^.

Các vấn đề liên quan