【问题标题】:Write to NSTasks standard input after launch启动后写入 NSTasks 标准输入
【发布时间】:2011-09-15 02:15:12
【问题描述】:

我目前正试图围绕 NSTask、NSPipe、NSFileHandle 业务的漏洞。所以我想我写一个小工具,可以编译和运行C代码。我还希望能够将我的标准输出和标准输入重定向到文本视图。

这是我到目前为止所得到的。 我使用这篇文章中的代码来重定向我的 stdio:What is the best way to redirect stdout to NSTextView in Cocoa?

NSPipe *inputPipe = [NSPipe pipe];
// redirect stdin to input pipe file handle
dup2([[inputPipe fileHandleForReading] fileDescriptor], STDIN_FILENO);
// curInputHandle is an instance variable of type NSFileHandle
curInputHandle = [inputPipe fileHandleForWriting];

NSPipe *outputPipe = [NSPipe pipe];
NSFileHandle *readHandle = [outputPipe fileHandleForReading];
[readHandle waitForDataInBackgroundAndNotify];
// redirect stdout to output pipe file handle
dup2([[outputPipe fileHandleForWriting] fileDescriptor], STDOUT_FILENO);

// Instead of writing to curInputHandle here I would like to do it later
// when my C program hits a scanf
[curInputHandle writeData:[@"123" dataUsingEncoding:NSUTF8StringEncoding]];

NSTask *runTask = [[[NSTask alloc] init] autorelease];
[runTask setLaunchPath:target]; // target was declared earlier
[runTask setArguments:[NSArray array]];
[runTask launch];

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(stdoutDataAvailable:) name:NSFileHandleReadCompletionNotification object:readHandle];

这里是 stdoutDataAvailable 方法

- (void)stdoutDataAvailable:(NSNotification *)notification
{
    NSFileHandle *handle = (NSFileHandle *)[notification object];
    NSString *str = [[NSString alloc] initWithData:[handle availableData] encoding:NSUTF8StringEncoding];
    [handle waitForDataInBackgroundAndNotify];
    // consoleView is an NSTextView
    [self.consoleView setString:[[self.consoleView string] stringByAppendingFormat:@"Output:\n%@", str]];
}

这个程序运行良好。它正在运行将标准输出打印到我的文本视图并从我的 inputPipe 读取“123”的 C 程序。就像我在上面的评论中指出的那样,我想在需要时在任务运行时提供输入。

所以现在有两个问题。

  1. 有没有办法在有人尝试从我的 inputPipe 读取数据时立即收到通知?
  2. 如果对 1 的回答是否定的,我可以尝试其他方法吗?也许使用 NSTask 以外的类?

非常感谢任何帮助、示例代码、其他资源的链接!

【问题讨论】:

    标签: objective-c redirect stdin nstask nsfilehandle


    【解决方案1】:

    我不确定您是否可以检测到 NSPipe 上的“拉动”。我确实有一种模糊的感觉,即使用select() 轮询写入可用性或使用kqueueNSFileHandle 的底层文件描述符上查找I/O 可用性事件可能会奏效,但我不是很熟悉以这种方式使用这些设施。

    您是否必须支持任意 C 程序,或者它是一个特殊的守护程序或您开发的东西?

    如果是您自己的程序,您可以关注outputPipe 的反馈请求,或者在您发现要发送的内容时将输入发送到inputPipe,然后让 C 程序在何时使用它准备好了;如果它是其他人的代码,您可以使用链接时方法(因为它是您正在编译的代码)来挂钩 scanf 和朋友,就像 附录 A-4 中描述的那样:

    http://www.cs.umd.edu/Library/TRs/CS-TR-4585/CS-TR-4585.pdf

    它的要点是使用您的自定义 I/O 函数创建一个.dylib(这可能会向您的应用发送一些标记,表明它们需要输入),将其链接到构建的程序中,设置一个环境变量(@ 987654331@) 启动任务,然后运行它。一旦你有了这些钩子,你就可以为你的宿主程序提供任何你想要的便利。

    【讨论】:

    • 感谢乔的回答。我最近再次解决了这个问题并让它工作(虽然不完全是我想要的)。我为命令行程序创建了一个小 GUI。当我运行命令行程序时,我将标准输出打印到 NSTextView,并且用户可以使用 NSTextField 提供输入。问题是即使程序不需要任何输入,用户也可以写入标准输入。这就是为什么如果每次子进程尝试从标准输入读取时我都能收到通知,那将是完美的。回答您的问题:是的,我想支持任意 C 程序。
    • 我将深入了解 select() 和 kqueue。看起来很有趣。自定义 I/O 函数也可以工作,但我不想使用它们。
    • 我不完全确定,在一般情况下,您是否可以知道程序是否需要输入。请记住,还有一些程序可以使用例如监视输入管道的活动。 select 或 kqueue(你好!)。附带说明一下,如果您愿意,可以将单个 NSTextView 用于输入和输出(请参阅PseudoTTY project 了解一些稍微旧但可能仍然有用的源代码)。 FWIW,我相信即使Terminal.app 也会很乐意接受输入,而不用关心正在运行的程序是否需要它,对吧?
    • 再次感谢。这一切都非常有帮助。我认为你是对的,即使程序可能不需要任何输入,用户也可以提供输入。
    猜你喜欢
    • 2018-02-21
    • 2012-08-24
    • 1970-01-01
    • 2011-07-23
    • 2016-07-11
    • 2014-03-06
    • 1970-01-01
    • 2012-06-08
    • 2014-10-29
    相关资源
    最近更新 更多