【问题标题】:How to script user input into program using read() syscall?如何使用 read() 系统调用将用户输入编写到程序中?
【发布时间】:2017-04-09 20:09:54
【问题描述】:

我正在 Linux 环境中使用几个二进制文件,并且正在尝试编写用户输入的脚本。例如,对于第一个程序 prog1.c:

void get_input() {

    int i;
    char buffer[32];

    i = 0;

    while (i < 3) {
        memset(buffer, 0, 32);
        printf("Enter input: ");
        fgets(buffer, 31, stdin);
        printf("Your input: %s\n", buffer);
        i++;
    }
}

我可以运行 prog1 并直接从控制台输入输入,也可以编写输入脚本并将其通过管道传输到程序中。

直接从控制台输入:

# ./prog1
Enter input: Stuff1
Your input: Stuff1

Enter input: Stuff2
Your input: Stuff2

Enter input: Stuff3
Your input: Stuff3

#

脚本输入:

# perl -e 'print "Stuff1\n" . "Stuff2\n" . "Stuff3\n"' | ./prog1
Enter input: Your input: Stuff1

Enter input: Your input: Stuff2

Enter input: Your input: Stuff3

#

虽然输出的格式有点乱,但程序还是显示了预期的输出。

我的问题在于第二个二进制 prog2.c:

void get_input() {

    int i;
    char buffer[32];

    i = 0;
    while (i < 3) {
        memset(buffer, 0, 32);
        printf("Enter input: ");
        read(0, buffer, 31);
        printf("Your input: %s\n", buffer);
        i++;
    }
}

当我可以直接从控制台输入我的输入时:

# ./prog2
Stuff1
Enter input: Your input: Stuff1

Stuff2
Enter input: Your input: Stuff2

Stuff3
Enter input: Your input: Stuff3

#

输入输入的提示不仅在我输入输入后才会显示,而且我什至无法编写输入脚本:

# perl -e 'print "Stuff1\n" . "Stuff2\n" . "Stuff3\n"' | ./prog2
Enter input: Your input: Stuff1
Stuff2
Stuff3

Enter input: Your input:
Enter input: Your input:
#

我对@9​​87654327@和read()之间的区别做了一些研究,发现:

  1. fgets() 是 C 函数,而 read() 是系统调用。
  2. fgets() 读取输入,直到遇到换行符或 EOF,而换行对 read() 系统调用没有相同的效果。
  3. read() 采用了某种fgets() 没有的缓冲机制。

我认为第 2 点和第 3 点与手头的问题最相关,但它们并没有提示我如何解决我的问题。

我需要给这些程序的用户输入涉及不可打印的十六进制字节,这就是为什么直接从控制台输入这样的输入是不够的。我也无法将源代码修改为二进制文件,因此没有解决方法只能使用fgets() 来收集输入。

我的问题是,是否有任何方法可以将输入输入 prog2,以便获得与 prog1 相同的行为。

谢谢。

【问题讨论】:

  • 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建最小、完整和可验证的示例。
  • 函数:fgets() 足够聪明,可以停止输入字节,同时仍有一个“备用”字节可供该函数在输入末尾放置 NUL ('\0') 字节.因此,缓冲区长度参数应该是缓冲区的实际长度
  • 问题完全变了。
  • 由于上面的 Olaf 的 cmets,它已被更改。基本问题仍然存在。

标签: c system-calls buffering


【解决方案1】:

read(2) 不缓冲,但 fgets/printf/etc from &lt;stdio.h&gt;do 以获得更好的性能。

如果您想阅读行文,请坚持使用fgets。但是,如果您想读取不可打印的数据块(即二进制),请使用fread。无论如何,请检查返回值。

【讨论】:

  • 调试时,在gdb中编写输入脚本时发现以下内容;这是 read() 调用后寄存器的状态: EAX: 0x15 ECX: 0xbffff60c ("Stuff1\nStuff2\nStuff3\n") 我可以从输出中猜到,但这并不能帮助我找到解决方法。
【解决方案2】:

读取“二进制”文件(可以包含 NUL 字节等)时,使用“read()”或“fread()”

读取文本文件时,使用 'fgets()'

【讨论】:

  • 我同意,但正如原始问题所述,我没有修改源的选项,所以我必须使用我所拥有的。
【解决方案3】:

我找到了解决此问题的方法。我仍然无法以我想要的方式与二进制文件交互 - 从控制台编写我的输入脚本 - 但我找到了一种以编程方式完成它的方法。

我正在使用一个 Python 库套件作为 subprocess 模块的包装器,但您可以简单地编写自己的:

p = subprocess.Popen(prog2, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

这会将二进制文件作为一个进程打开,然后您可以使用 Python 脚本中的发送和接收函数与之交互。

我希望这可以帮助遇到类似问题的其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    相关资源
    最近更新 更多