【问题标题】:Python. Redirect stdout to a socketPython。将标准输出重定向到套接字
【发布时间】:2014-02-21 04:57:37
【问题描述】:

我在计算机“A”上运行我的脚本。然后我通过我的脚本从计算机“B”连接到计算机“A”。我将消息发送到计算机“A”,我的脚本使用 exec() 指令运行它。

我想通过计算机“B”上的套接字查看在计算机“A”上执行我的消息的结果。

我尝试更改sys.stdout = socket_response但出现错误:“Socket object has no attribute write()”

那么,如何通过套接字连接将标准输出(printexec())从计算机“A”重定向到计算机“B”?

这将是我脚本中的某种“python 解释器”。

抱歉,我无法在没有声誉的情况下回答我自己的问题

谢谢大家!

我使用@Torxed 建议我的简单方法。这是我的伪代码(只是一个例子,不是我的真实脚本)

    #-*-coding:utf-8-*-
import socket
import sys

class stdout_():

    def __init__(self, sock_resp):
        self.sock_resp = sock_resp

    def write(self, mes):
        self.sock_resp.send(mes)


MY_IP = 'localhost'
MY_PORT = 31337

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Start server")
old_out = sys.stdout


srv.bind((MY_IP, MY_PORT))
srv.listen(0)
sock_resp, addr_resp = srv.accept()
new_out = stdout_(sock_resp)
sys.stdout = new_out
#sys.stdout = sock_resp ### sock_object has no attribute 'write'
while 1:
    try:
        a = sock_resp.recv(1024)
        exec(a)
    except socket.timeout:
        #print('server timeout!!' + '\n')
        continue

我用 Putty 连接到脚本并发送“print 'abc'”,然后我收到了答案 'abc'。

【问题讨论】:

  • 你写一个包装类怎么样,你可以把你的sys.stdout指向它,它有一个叫做write()的函数,基本上就是这样:self.socket.send(data),一切都很好? :)
  • 是的,我想过,但可能有更标准的方式?
  • 另外,我可能会考虑使用subprocess.Popen() 而不是exec(),因为您将能够更有效地处理命令的输入/输出。我知道没有标准的方法,希望一些大师知道:)
  • @Torxed 我就是这样做的。您可能希望将您的评论变成答案。
  • 是的,希望...但我必须稍微解释一下情况。我有一个“my_script”,应该可以永久使用。而且我不能总是在附近。但是我需要将变量更改为脚本而不停止它。我想——这种方式很简单,但我错了……

标签: python sockets redirect stdout


【解决方案1】:

Python的socket类中有makefile函数:

socket.ma​​kefile(mode='r', buffering=None, *, encoding=None, 错误=无,换行=无)

返回一个与套接字关联的文件对象。准确返回 类型取决于给 makefile() 的参数。这些论据是 与内置 open() 函数的解释方式相同。

关闭文件对象不会关闭套接字,除非没有 其余对套接字的引用。套接字必须处于阻塞状态 模式;它可以有一个超时,但文件对象的内部缓冲区可能 如果发生超时,最终会处于不一致的状态。

您可以在 Mark Lutz 的书 (chapter 12, "Making Sockets Look Like Files and Streams") 中了解如何使用它。

书中的一个例子(想法很简单:从带有socket.makefile 的套接字创建一个文件对象并将sys.stdout 链接到它):

def redirectOut(port=port, host=host):
    """
    connect caller's standard output stream to a socket for GUI to listen
    start caller after listener started, else connect fails before accept
    """
    sock = socket(AF_INET, SOCK_STREAM)
    sock.connect((host, port))                # caller operates in client mode
    file = sock.makefile('w')                 # file interface: text, buffered
    sys.stdout = file                         # make prints go to sock.send
    return sock                               # if caller needs to access it raw

【讨论】:

  • @gek0n 尝试使用 0 大小的缓冲区(对于 python2):file = sock.makefile('w', 0) 或使用 buffering=None 对于 python3:file = sock.makefile('w', buffering=None)
【解决方案2】:

服务器端:

from subprocess import Popen, STDOUT, PIPE
from socket import socket
from time import sleep

server_sock = socket()
server_sock.bind(('', 8000))
server_sock.listen(4)

def close_process(p):
    p.stdin.close()
    p.stdout.close()

while 1:
    try:
        client, client_address = server_sock.accept()
        data = client.recv(8192)
    except:
        break
    # First, we open a handle to the external command to be run.
    process = Popen(data.decode('utf-8'), shell=True, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
    # Wait for the command to finish
    # (.poll() will return the exit code, None if it's still running)
    while process.poll() == None:
        sleep(0.025)
    # Then we send whatever output the command gave us back via the socket
    # Python3: sockets never convert data from byte objects to strings,
    # so we'll have to do this "manually" in case you're confused from Py2.X
    try:
        client.send(bytes(process.stdout.read(), 'UTF-8'))
    except:
        pass

    # And finally, close the stdout/stdin of the process,
    # otherwise you'll end up with "to many filehandles openened" in your OS.
    close_process(process)
    client.close()

server_sock.close()

这假设是 Python3。

如果没有其他人有更好的方法将输出从进程重定向到套接字,那么这是您可以使用的解决方案。

【讨论】:

  • 非常感谢,但我可以从另一个线程更改“my_script”中的变量吗?
  • 线程?你从不为线程感到难过吗?您可以(从客户端)发送变量更新是的,但您需要 eval()(不是 exec)来更新服务器脚本中的运行时变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-15
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多