我是python的新手,但我可以进行编码和调试。在过去的几天里,我的头脑中出现了以下问题并寻找答案。任何帮助深表感谢。 任务:我想做一个交互式telnet(我知道有一个telnet库,但由于各种原因我们没有使用它)。 为此,我使用subprocess.popen
p = subprocess.Popen(telnet_command,
stdin = subprocess.PIPE,
stdout = outputfileobj,
stderr = errorfileobj)
我执行poll()以查看服务器是否已连接到会话。一旦我验证了,我就继续写入stdin进行交互式通信。
inputTxt = 'GET / HTTP/1.1\nHost: ' + hostheader + '\n\n'
p.stdin.write(inputTxt)
p.stdin.flush()
这是问题发生的地方。我得到http响应(或至少输出)5/6次但是1/6时间,我没有得到输出并且子进程被终止 - 这是不可能的。
我为失败案例运行了系统跟踪,请在下面找到相同的内容。
16129 write(7, "GET / HTTP/1.1\nHost: www.google."..., 37) = 37
16129 gettimeofday({1310538497, 134474}, NULL) = 0
16129 futex(0x81993a8, FUTEX_WAKE, 1) = 0
16129 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16129 fstat64(4, {st_mode=S_IFREG|0644, st_size=520689, ...}) = 0
16129 _llseek(4, 520689, [520689], SEEK_SET) = 0
16129 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16129 write(4, "2011-07-13 06:28:17,134 : pconns"..., 170) = 170
16129 futex(0x81d3b30, FUTEX_WAKE, 1) = 0
16129 waitpid(16198, 0xffa945e8, WNOHANG) = 0
16129 gettimeofday({1310538497, 135160}, NULL) = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf74b9000
16129 _llseek(6, 0, [0], SEEK_SET) = 0
16129 fstat64(6, {st_mode=S_IFREG|0644, st_size=81, ...}) = 0
16129 _llseek(6, 0, [0], SEEK_CUR) = 0
16129 read(6, "Trying 74.125.236.48...\nConnecte"..., 4096) = 81
16129 read(6, "", 4096) = 0
16129 close(6) = 0
16129 munmap(0xf74b9000, 4096) = 0
16129 gettimeofday({1310538497, 135778}, NULL) = 0
16129 futex(0x81993a8, FUTEX_WAKE, 1) = 0
16198 <... select resumed> ) = 1 (in [0])
16198 read(0, "GET / HTTP/1.1\nHost: www.google."..., 8191) = 37
16129 stat64("/etc/localtime", <unfinished ...>
16198 ioctl(1, TCFLSH, 0) = -1 ENOTTY (Inappropriate ioctl for device)
16129 <... stat64 resumed> {st_mode=S_IFREG|0644, st_size=56, ...}) = 0
16198 select(4, [0 3], [3], [3], {0, 0}) = 1 (out [3], left {0, 0})
16129 fstat64(4, {st_mode=S_IFREG|0644, st_size=520859, ...}) = 0
16198 send(3, "GET / HTTP/1.1\r\nHos\377\363\377\375\6", 24, 0 <unfinished ...>
16129 _llseek(4, 520859, <unfinished ...>
16198 <... send resumed> ) = 24
16198 select(4, [0 3], [3], [3], {0, 0} <unfinished ...>
16129 <... _llseek resumed> [520859], SEEK_SET) = 0
16198 <... select resumed> ) = 1 (out [3], left {0, 0})
16198 send(3, ": www.google.com\r\n\r\n", 20, 0 <unfinished ...>
16129 stat64("/etc/localtime", <unfinished ...>
16198 <... send resumed> ) = 20
如果仔细查看 16198行(3,“GET / HTTP / 1.1 \ r \ nHos \ 377 \ 363 \ 377 \ 375 \ 6”,24,0 中的行,字符串“Hos t ”被一些“Hos \ 377 \ 363 \ 377 \ 375 \ 6 ”取代。我不知道为什么会出现这种情况。虽然这也关闭了我建立的telnet连接。如果您需要更多数据,请告诉我。
答案 0 :(得分:1)
如果您尝试使用communicate()
方法将数据发送到子流程而不是使用stdin会怎么样,因为后者不被Python's documentation阻止:
警告:使用communic()而不是.stdin.write,.stdout.read或 .stderr.read以避免由于任何其他OS管道导致的死锁 缓冲填充和阻止子进程。
试试这个:
p.communicate(input='GET / HTTP/1.1\nHost: ' + hostheader + '\n\n')
答案 1 :(得分:1)
虽然沟通更好,但如果你真的必须使用 stdin.write ,你可以使用以下方式进行非阻塞调用:
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
为了更好地理解,请阅读:
答案 2 :(得分:0)
如果不需要交互,则不用交流,而是将文本提前放入管道中。 我还没有找到更多的pythonic“ text_to_stream”。
import os
import sys
import subprocess
def text_to_stream(text):
p = os.pipe()
os.write(p[1], text.encode('utf-8'))
os.close(p[1])
return os.fdopen(p[0], "r")
def run(cmd, stdin_text=None):
stdin = text_to_stream(stdin_text) if stdin_text else sys.stdin
result = subprocess.run(
cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=stdin)
result.check_returncode()