Python 如何将 INET 套接字连接到 PTY 设备
How to connect INET socket to PTY device in Python
我正在尝试在 Python:
中复制此 socat
命令的行为
socat PTY,link=/tmp/mypty tcp-listen:1234
到服务器端口1234的TCP连接将连接到/tmp/mypty(link到/dev/pts/N),运行 screen /tmp/mypty
将允许用户与该连接另一端的任何内容进行交互。换句话说,如果这个用于连接到那个监听端口:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp-connect:172.16.30.3:1234
然后 运行 screen /tmp/mypty
将用户连接到 TCP 连接另一端的 bash
运行 的实例。
获取 TCP 套接字很简单。我可以使用 os.openpty() 获得 PTY,这会产生一对文件描述符,它们只是整数。
我无法做的是以一种可以无缝地来回传递数据的方式挂接套接字和 ose 文件描述符。如果它们都是套接字,那将是微不足道的;使用带有 select() 的循环将新的 read 数据传递给另一个套接字的 write.
我尝试过的:
- 使用 socket.fromfd 使用 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 没有区别。
- 使用 os.dup2() 将 SSLsocket 的 fileno() 映射到标准输入、标准输出和标准错误,然后 运行 os.openpty()(la tcp_pty_bind.py).这不会产生任何错误,但是当我使用
screen
. 打开 PTY 时没有明显的数据流
Almost 所有 Python PTY 示例都集中在 pty.spawn() 上,因此很难找到这种(不可否认)使用的任何示例代码PTY 的。
旁注:我使用 os.openpty 而不是 pty.openpty 只是因为这似乎没有意义。 pty 模块似乎被宣传为具有更高的可移植性,但没有更多的可移植性,我正在研究 Linux,因此可移植性不是问题。而且由于我正在为正确的 os.ttyname() 获取有效的文件描述符,所以我没有理由质疑 openpty() 是否工作不正常。
这可以使用 select.poll() 而不是 select.select() 来完成,因为 select.poll() 将适用于文件描述符和套接字。
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() 作为文件描述符,然后以相同的方式对待双方(os.read(), os.write()).但是,如果您要将它与 SSLSocket 一起使用,则需要上面更复杂的版本,因为如果您从 SSLSocket 中获取 fileno(),它会期望您将处理 TLS 层和数据。
我正在尝试在 Python:
中复制此socat
命令的行为
socat PTY,link=/tmp/mypty tcp-listen:1234
到服务器端口1234的TCP连接将连接到/tmp/mypty(link到/dev/pts/N),运行 screen /tmp/mypty
将允许用户与该连接另一端的任何内容进行交互。换句话说,如果这个用于连接到那个监听端口:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp-connect:172.16.30.3:1234
然后 运行 screen /tmp/mypty
将用户连接到 TCP 连接另一端的 bash
运行 的实例。
获取 TCP 套接字很简单。我可以使用 os.openpty() 获得 PTY,这会产生一对文件描述符,它们只是整数。
我无法做的是以一种可以无缝地来回传递数据的方式挂接套接字和 ose 文件描述符。如果它们都是套接字,那将是微不足道的;使用带有 select() 的循环将新的 read 数据传递给另一个套接字的 write.
我尝试过的:
- 使用 socket.fromfd 使用 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 没有区别。
- 使用 os.dup2() 将 SSLsocket 的 fileno() 映射到标准输入、标准输出和标准错误,然后 运行 os.openpty()(la tcp_pty_bind.py).这不会产生任何错误,但是当我使用
screen
. 打开 PTY 时没有明显的数据流
Almost 所有 Python PTY 示例都集中在 pty.spawn() 上,因此很难找到这种(不可否认)使用的任何示例代码PTY 的。
旁注:我使用 os.openpty 而不是 pty.openpty 只是因为这似乎没有意义。 pty 模块似乎被宣传为具有更高的可移植性,但没有更多的可移植性,我正在研究 Linux,因此可移植性不是问题。而且由于我正在为正确的 os.ttyname() 获取有效的文件描述符,所以我没有理由质疑 openpty() 是否工作不正常。
这可以使用 select.poll() 而不是 select.select() 来完成,因为 select.poll() 将适用于文件描述符和套接字。
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() 作为文件描述符,然后以相同的方式对待双方(os.read(), os.write()).但是,如果您要将它与 SSLSocket 一起使用,则需要上面更复杂的版本,因为如果您从 SSLSocket 中获取 fileno(),它会期望您将处理 TLS 层和数据。