macos – 从Cocoa应用程序控制交互式命令行实用程序 – 与ptys有关

macos – 从Cocoa应用程序控制交互式命令行实用程序 – 与ptys有关,第1张

概述我想做什么 我的Cocoa应用程序需要运行一堆命令行程序.其中大多数都是非交互式的,所以我用一些命令行参数启动它们,它们做它们的事情,输出一些东西然后退出.其中一个程序是交互式的,所以它输出一些文本和stdout的提示,然后期望stdin上的输入,这一直持续到你发送一个退出命令. 什么有效 非交互式程序只是将大量数据转储到stdout然后终止,这些程序相对简单: >为stdout / stdin 我想做什么

我的@L_419_0@应用程序需要运行一堆命令行程序.其中大多数都是非交互式的,所以我用一些命令行参数启动它们,它们做它们的事情,输出一些东西然后退出.其中一个程序是交互式的,所以它输出一些文本和stdout的提示,然后期望stdin上的输入,这一直持续到你发送一个退出命令.

什么有效

非交互式程序只是将大量数据转储到stdout然后终止,这些程序相对简单:

>为stdout / stdin / stderr创建NSPipes
>使用这些管道启动NSTask

然后,要么

>获取管道另一端的NSfileHandle以读取所有数据,直到流结束并在任务结束时一次性处理

要么

>从输出管道另一端的NSfileHandle获取-fileDescriptors.
>将文件描述符设置为使用非阻塞模式
>使用dispatch_source_create(disPATCH_SOURCE_TYPE_READ,…创建每个文件描述符的GCD调度源)
>使用read()恢复调度源并处理它抛出的数据
>继续前进,直到任务结束,管道文件描述符报告EOF(read()报告0字节读取)

什么行不通

这两种方法都完全打破了交互式工具.显然我不能等到程序退出,因为它位于命令提示符下,除非我告诉它,否则永远不会退出.另一方面,NSPipe缓冲数据,因此您以缓冲区大小的块接收它,除非Cli程序恰好刷新管道,在我的情况下不会.初始命令提示符比缓冲区大小小得多,所以我没有收到任何东西,它只是坐在那里.所以NSPipe也是一个禁忌.

在some research之后,我确定我需要使用伪终端(pty)代替NSPipe.不幸的是,我一无所获,只能让它运转起来.

我试过的

而不是stdout管道,我创建一个像这样的pty:

struct termios termp;bzero(&termp,sizeof(termp));int res = openpty(&masterFD,&slaveFD,NulL,&termp,NulL);

这给了我两个文件描述符;我将slaveFD交给NSfileHandle,它被传递给NSTask,用于stdout或stdout和stdin.然后我尝试从主方进行通常的异步读取.

如果我运行我在终端窗口中控制的程序,它会通过输出2行文本开始,一行18字节长,包括换行符,一个22字节,并且没有命令提示符的换行符.在那40个字节之后,它等待输入.

如果我只是将pty用于stdout,我会从受控程序中收到18个字节的输出(恰好是一行,以换行符结尾),而不是更多.在最初的18个字节后,所有东西都只是位于那里,没有更多的事件 – GCD事件源的处理程序不会被调用.

如果我也将pty用于stdin,我通常会收到19个字节的输出(前面提到的行加上下一行的一个字符),然后受控程序立即死掉.如果我在尝试读取数据之前稍等一下(或者调度噪声导致一个小的暂停),我实际上会在程序再次立即死亡之前得到整个40个字节.

另一个死胡同

有一次我想知道我的异步读取代码是否有缺陷,所以我使用NSfileHandles及其-readInBackgroundAndNotify方法重新做了一切.这与使用GCD时的行为相同. (我最初在NSfileHandle API上选择了GCD,因为在NSfileHandle中似乎没有任何异步写入支持)

问题

经过一天徒劳无功的尝试到达这一点,我可以做一些帮助.我正在尝试做什么有一些基本问题吗?为什么将stdin连接到pty终止程序?我没有关闭pty的主端,所以它不应该接收EOF.抛开stdin,为什么我只得到一行的产出?我在pty的文件描述符上执行I / O的方式有问题吗?我是否正确使用主站和从站结束 – 在控制过程中掌握,NSTask中的从站?

我还没有尝试过

到目前为止,我只在管道和ptys上执行了非阻塞(异步)I / O.我唯一能想到的是pty根本不支持它. (如果是这样,为什么fcntl(fd,F_SETFL,O_NONBLOCK);虽然成功了?)我可以尝试在后台线程上阻塞I / O并将消息发送到主线程.我希望避免不得不处理多线程,但考虑到所有这些API的破坏程度,它不会比尝试另一种异步I / O排列更耗时.不过,我很想知道我到底做错了什么.

解决方法

The problem is likely that the stdio library insIDe is buffering output. The output will only appear in the read pipe when the command-line program flushes it,either because it writes a “\n” via the stdio library,or fflush()s,or the buffer gets full,or exits (which causes the stdio library to automatically flush any output still buffered),or possibly some other conditions. If those printf strings were “\n”-terminated,then you MIGHT the output quicker. That’s because there are three output buffering styles — unbuffered,line-buffered (\n causes a flush),and block buffered (when the output buffer gets full,it’s auto-flushed).

Buffering of stdout is line-buffered by default if the output file descriptor is a tty (or pty); otherwise,block buffered. stderr is by default unbuffered. The setvbuf() function is used to change the buffering mode. These are all standard BSD UNIX (and maybe general UNIX) things I’ve described here.

NSTask does not do any setting up of ttys/ptys for you. It wouldn’t help in this case anyway since the printfs aren’t printing out \n.

Now,the problem is that the setvbuf() needs to be executed insIDe the command-line program. Unless (1) you have the source to the command-line program and can modify it and use that modifIEd program,or (2) the command-line program has a feature that allows you to tell it to not buffer its output [IE,call setvbuf() itself],there’s no way to change this,that I kNow of. The parent simply cannot affect the subprocess in this way,either to force flushing at certain points or change the stdio buffering behavior,unless the command-line utility has those features built into it (which would be rare).

资料来源:Re: NSTask,NSPipe’s and interactive UNIX command

总结

以上是内存溢出为你收集整理的macos – 从Cocoa应用程序控制交互式命令行实用程序 – 与ptys有关全部内容,希望文章能够帮你解决macos – 从Cocoa应用程序控制交互式命令行实用程序 – 与ptys有关所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1016354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存