我正在尝试从 发送消息kafka-console-producer.sh
,即
#!/bin/bash
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
export KAFKA_HEAP_OPTS="-Xmx512M"
fi
exec $(dirname $0)/kafka-run-class.sh kafka.tools.ConsoleProducer "$@"
然后我通过 Putty 终端粘贴消息。在接收端,我看到消息被截断为大约 4096 字节。我在 Kafka 中没有看到任何地方设置了这个限制。
这个限制可以来自 bash/terminal 或 Putty 吗?
答案1
4095 是 Linux 上 tty 行规则内部编辑器长度的限制。从termios(3)
手册页:
- 最大行长度为 4096 个字符(包括终止换行符);超过 4096 个字符的行将被截断。在 4095 个字符之后,输入处理(例如,ISIG 和 ECHO* 处理)将继续,但在 4095 个字符之后直到(但不包括)任何终止换行符的任何输入数据都将被丢弃。这确保了终端始终可以接收更多输入,直到至少可以读取一行。
另请参阅Linux内核中对应的代码。
例如,如果您输入:
$ wc -cEnter
Enter在 shell 自己的行编辑器(在 bash 中为 readline)中将行提交给 shell。当命令行完成时,shell 已准备好执行它,因此它会留下自己的行编辑器,将终端设备放回规范(又名煮熟的) 模式,它启用粗略的行编辑器(实际上在内核中的 tty 驱动程序中实现)。
然后,如果您粘贴 5000 字节的行,请按Ctrl+D提交该行,并再次告诉wc
您已完成,您将看到4095
输出。
(请注意,该限制不适用于bash
自己的行编辑器,您会发现可以在 shell 提示符下粘贴更多数据bash
)。
因此,如果您的接收应用程序从其标准输入读取输入行,并且其标准输入是终端设备,并且该应用程序没有实现自己的行编辑器(就像这样bash
做)并且不更改输入模式,那么您将无法输入长度超过 4096 字节的行(包括终止换行符)。
stty -icanon
但是,您可以在启动接收应用程序之前禁用终端设备的行编辑器(使用),以便它在您输入时直接读取输入。但是,您将无法使用Backspace/ Ctrl+W来编辑输入,也无法使用Ctrl+D来结束输入。
如果您输入:
$ 已保存=$(stty -g); stty -icanon icrnl;头-n1 |厕所-c; stty“$已保存”Enter
粘贴 5000 字节长的行并按Enter,您将看到 5001。
答案2
正如 Stéphane Chazelas 的回答中提到的,终端驱动程序的输入编辑缓冲区的大小有限。
您可以将输出重定向kafka-console-producer.sh
到文件,而不是粘贴到终端:
kafka-console-producer.sh > kafka.out
然后将文件上传到服务器,并将其用作您要将输入粘贴到的任何程序的输入。
some-program < kafka.out
答案3
是的,命令行长度有限制,或者更准确地说,传递给 的参数的长度有限制execve
。另请参阅“人执行”。
很久以前,这个限制是 128kB。在现代内核中,它要高得多。
所以你截断到 4096 与此无关。
实际上,命令行永远不会被默默地截断。如果参数对于 来说太长execve
,调用将会失败。
答案4
这可能是题外话,因为问题是为什么/在哪里,而不是如何。无论如何,我都会被提示写这个,因为我目前可以找到一个错误的、已经被投票的答案(由于匆忙阅读问题而产生),建议将消息输出到文件,然后将该文件定向到脚本。
Stéphane Chazelas 很好地回答了实际问题,即 4095 个字符+输入长度的新行限制来自硬编码的 Linux 内核对终端如何在规范模式下工作的限制(终端通常处于规范模式)。
为了在具体设置中进一步演示这一点(提供如何问题的答案),我们可以修复脚本kafka-console-producer.sh
以摆脱限制,如下所示:
#!/bin/bash
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
export KAFKA_HEAP_OPTS="-Xmx512M"
fi
tty_orig=$(stty -g)
stty -icanon
$(dirname $0)/kafka-run-class.sh kafka.tools.ConsoleProducer "$@"
stty "$tty_orig"
这样,可以将更长的消息连续粘贴到脚本中,而不会在 4095 个字符处被截断。kafka-console-producer.sh
如果原始脚本来自 Kafka 应用程序套件并且您不想编辑它,您还可以创建一个调用原始脚本的包装器脚本。