我运行一个线程从标准输入读取数据,然后将其转发到套接字。套接字是可选择的,因此标准输入也是可选择的。
在最近的项目中,我必须不断地从一个网络套接字读取数据,然后将其转发到另一个套接字,直到用户从控制台输入q
为止。有人可能会想使用线程,但我不想处理多线程的问题。最后,我找到了一种不太清晰的解决方案,而且它起作用了。
我创建了一个线程 - 是的,线程,但没有多线程的问题 - 这个线程打开一个监听随机端口的服务器套接字,然后打开一个连接到该服务器的客户端套接字。服务器套接字接受连接,然后以阻塞方式调用 sys.stdin.read()
,所有从标准输入中读取的数据都将写入已接受的连接中。因此,客户端套接字接收从标准输入读取的数据。现在,客户端套接字是可选择的标准输入,并且它是线程安全的。
源代码:
""" === Windows stdio ===
@author ideawu@163.com
@link http://www.ideawu.net/
File objects on Windows are not acceptable for select(),
this module creates two sockets: stdio.s_in and stdio.s_out,
as pseudo stdin and stdout.
@example
from stdio import stdio
stdio.write('hello world')
data = stdio.read()
print stdio.STDIN_FILENO
print stdio.STDOUT_FILENO
"""
import thread
import sys, os
import socket
def __sock_stdio():
def stdin_thread(sock, console):
""" read data from stdin, and write the data to sock
"""
try:
fd = sys.stdin.fileno()
while True:
data = os.read(fd, 1024)
if not data:
break
while True:
nleft = len(data)
nleft -= sock.send(data)
if nleft == 0:
break
except:
pass
sock.close()
def stdout_thread(sock, console):
""" read data from sock, and write to stdout
"""
try:
fd = sys.stdout.fileno()
while True:
data = sock.recv(1024)
if not data:
break
while True:
nleft = len(data)
nleft -= os.write(fd, data)
if nleft == 0:
break
except:
pass
sock.close()
class Console:
def __init__(self):
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serv.bind(('127.0.0.1', 0))
self.serv.listen(5)
port = self.serv.getsockname()[1]
self.stdin_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.stdin_sock.connect(('127.0.0.1', port))
self.s_in, addr = self.serv.accept()
self.STDIN_FILENO = self.s_in.fileno()
thread.start_new_thread(stdin_thread, (self.stdin_sock, self))
self.read_str = ''
def close(self):
self.s_in.close()
self.s_out.close()
self.stdin_sock.close()
self.stdout_sock.close()
self.serv.close()
def write(self, data):
try:
return self.s_out.send(data)
except:
return -1
def read(self):
try:
data = self.s_in.recv(4096)
except:
return ''
ret = self.read_str + data
self.read_str = ''
return ret
def readline(self):
while True:
try:
data = self.s_in.recv(4096)
except:
return ''
if not data:
return ''
pos = data.find('\n')
if pos == -1:
self.read_str += data
else:
left = data[0 : pos + 1]
right = data[pos + 1 : ]
ret = self.read_str + left
self.read_str = right
return ret
stdio = Console()
return stdio
def __os_stdio():
class Console:
def __init__(self):
self.STDIN_FILENO = sys.stdin.fileno()
self.STDOUT_FILENO = sys.stdout.fileno()
def close(self):
pass
def write(self, data):
try:
return os.write(self.STDOUT_FILENO, data)
except:
return -1
def read(self):
try:
return os.read(self.STDIN_FILENO, 4096)
except:
return ''
def readline(self):
try:
return sys.stdin.readline()
except:
return ''
stdio = Console()
return stdio
if os.name == 'posix':
stdio = __os_stdio()
else:
stdio = __sock_stdio()