Python中如何将INET socket连接到PTY设备

2024-09-27 07:29:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在Python中复制这个socat命令的行为:

socat PTY,link=/tmp/mypty tcp-listen:1234

到服务器端口1234的TCP连接将连接到/tmp/mypty(指向/dev/pts/N的链接),运行screen /tmp/mypty将允许用户与该连接另一端的任何内容进行交互。换句话说,如果这用于连接到该侦听端口:

^{pr2}$

然后运行screen /tmp/mypty将用户连接到在TCP连接的另一端运行的bash的实例。在

获取TCP套接字很简单。我可以找个私人助理来用操作系统openpty(),这会产生一对文件描述符,它们只是整数。在

我做不到的是用一种无缝地来回传递数据的方式钩住套接字和那些文件描述符。如果这两个套接字都是,那么这将是微不足道的;使用带有select()的循环将新的read数据传递给另一个套接字的write。在

我所做的:

  1. 使用来自FD的插座使用PTY文件描述符之一构建套接字。这将导致OSError: [Errno 88] Socket operation on non-socket。此代码的示例,其中clisock是有效的套接字:

    def sockToPty(clisock,addr):
        (master, slave) = os.openpty()
        print('PTY: Opening {}'.format(os.ttyname(slave)))
        ptymsock = socket.fromfd(master, socket.AF_UNIX, socket.SOCK_STREAM)
        ptyssock = socket.fromfd(slave,  socket.AF_UNIX, socket.SOCK_STREAM)
        print('CLISOCK: {}'.format(clisock))
        print('PTYMSOCK: {}'.format(ptymsock))
        print('PTYSSOCK: {}'.format(ptyssock))
        peer[clisock] = ptymsock
        peer[ptyssock] = clisock
        while True:
            iready, oready, eready = select.select([clisock, ptyssock], [], [])

            for sock in iready:
                data = sock.recv(4096)
                if not len(data):
                    return
                peer[sock].send(data)

从而导致此错误:


    PTY: Opening /dev/pts/2
    CLISOCK: 
    PTYMSOCK: 
    PTYSSOCK: 
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
        self.run()
      File "/usr/lib/python3.6/threading.py", line 864, in run
        self._target(*self._args, **self._kwargs)
      File "./tcpmux.py", line 62, in sockToPty
        peer[sock].send(data)
    OSError: [Errno 88] Socket operation on non-socket

如果我使用AF_INET而不是AF_UNIX,也没有什么不同。在

  1. 使用操作系统2()将SSLsocket的fileno()映射到stdin、stdout和stderr,然后运行操作系统openpty()(一个latcp_pty_bind.py)。这不会产生任何错误,但是当我使用screen打开PTY时,没有明显的数据流。在

几乎所有Python PTY示例都集中在pty.产卵(),这使得很难找到PTY的这种(公认的晦涩)用法的示例代码。在

旁注:我正在使用操作系统openpty而不是私人有限公司只是因为似乎没有意义。pty模块似乎被宣传为具有更多的可移植性,但并不是要有更多的可移植性,而且我正在研究Linux,所以可移植性不是一个问题。既然我得到了正确的文件描述符操作系统名称(),我没有理由质疑openpty()不能正常工作。在


Tags: 文件informatsockettmp描述符sockpty
1条回答
网友
1楼 · 发布于 2024-09-27 07:29:01

可以使用选择投票()而不是选择。选择(),因为选择投票()将同时使用文件描述符和套接字。在

def sockToPty(clisock,addr):
    (master, slave) = os.openpty()
    tty.setraw(master, termios.TCSANOW)
    print('PTY: Opened {} for {}'.format(os.ttyname(slave), addr))
    mypoll = select.poll()
    mypoll.register(clisock, select.POLLIN)
    mypoll.register(master, select.POLLIN)
    try:
        while True:
            fdlist = mypoll.poll(1000)
            for fd,event in fdlist:
                # We treat sockets and FDs differently
                if fd == master:
                    data = os.read(fd, 4096)
                    if len(data) == 0:
                        print('PTY: {}, {} exiting due to Zero read.'.format(addr, os.ttyname(slave)))
                        raise GetOut
                    clisock.send(data)
                else:
                    data = clisock.recv(4096)
                    if len(data) == 0:
                        print('PTY: {}, {} exiting due to Zero read.'.format(addr, os.ttyname(slave)))
                        raise GetOut
                    os.write(master, data)
    except GetOut:
        os.close(master)
        os.close(slave)
        clisock.shutdown(socket.SHUT_RDWR)
        clisock.close()

这段代码比简单套接字所需的代码复杂得多—对于TCP套接字,您可以简单地将该套接字的fileno()用作文件描述符,然后以相同的方式对待两边(操作系统读取(), 操作系统写入()). 但是,如果要在SSLSocket中使用它,则需要上面更复杂的版本,因为如果从SSLSocket获取fileno(),那么它期望您处理TLS层和数据。在

相关问题 更多 >

    热门问题