python - 如何启动连接到您正在监听的套接字的进程?

标签 python multithreading sockets tcp

我有一个进程,我的代码从 subprocess.Popen() 启动,它尝试连接到我的代码也在监听的套接字。问题是如果代码首先开始监听此套接字,则它无法启动子进程。被sock.accept()阻塞,当sock.accept()超时,subprocess.Popen()<时明显没有监听 运行。如果代码首先启动子进程,它会尝试连接到套接字,但在任何代码能够监听它之前就失败了。

现在..我有什么想法可以做到这一点吗?看起来我需要以非阻塞方式开始监听,然后启动进程,但我有点困惑,因为即使我使用 select() 来处理队列,最终 sock.accept() 被调用并且因此阻止了代码...我认为。

无论如何,一些方向会非常方便!我宁愿不这样做,但如果它能让生活更轻松,我也不反对使用 Twisted。

编辑 1: 我将尝试以代码的方式进行改进,我必须查看我的旧提交以找到一个工作版本。不过基本上,我不认为我的代码是问题所在。我认为我只是实现错误。

例如,如果我启动我的套接字监听器并在 shell 中手动启动此 subprocess.Popen() 进程,它连接得很好。这是因为 shell 已经在监听。我相信我的问题只是先有鸡还是先有蛋的问题。在我的代码中,在单个代码路径中,如果我首先启动进程,它会立即失败,因为还没有 没有套接字服务器在监听。但是,如果我首先启动套接字服务器,它会超时,因为它正在阻塞,并且在它完成阻塞之前不会启动任何子进程。我相信,我的解决方案在于非阻塞代码,但我非常不熟悉如何正确实现这一点。我看到很多关于 select() 的提及,但它们看起来它们会在同一点阻塞,sock.accept()。我说“看起来像”是因为我还没有实现 select() 版本。我在这里可能是错的,如果我错了,请告诉我。

编辑 2: 这是代码的套接字部分。请注意,这当前设置为非阻塞。

 90         # Create our socket stream to listen on.
 91         serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 92
 93         #serv.settimeout(5)
 94         serv.setblocking(0)
 95
 96         # Bind the address.
 97         serv.bind(('', self.PORT))
 98         serv.listen(5)
 99
100         try:
101             # Now start listening for a connection!
102             (self._sock, remote_address) = serv.accept()
103         except socket.timeout:
104             logger.debug('Socket connection failed!')
105             raise DBGPServerNotFoundError(
106                 'No connection was established coming from '
107                 '"%(address)s:%(port)i".' % {
108                     'address':self.ADDRESS,
109                     'port':self.PORT,
110                 })
111         else:
112             logger.debug('Socket connection established! The other end of '
113                          'the connection is at "%s:%i".' % remote_address)
114         finally:
115             serv.close()

这里是错误..

  File "/home/lee/projects/vim-debug/repo/vimbug/dbgp.py", line 100, in connect
    (self._sock, remote_address) = serv.accept()
  File "/usr/lib/python2.6/socket.py", line 197, in accept
    sock, addr = self._sock.accept()
error: [Errno 11] Resource temporarily unavailable

子进程启动代码在不同的模块中(特别是单元测试),但这里是为了很好的衡量标准。注意con是一个容器对象,con.connect()是上面代码的函数。

 56     con.connect()
 57     pydbgp_proc = subprocess.Popen(
 58         ('pydbgp.py', '-d', 'localhost:%i' % OPTIONS['pydbgp_port'],
 59         OPTIONS['debug_file']),
 60         stdout=subprocess.PIPE,
 61         stderr=subprocess.PIPE,)

编辑 3: 稍微重写代码以尝试在 sock.accept() 被调用之前连接到套接字。我们会看看它是否失败:)

编辑 4: 好吧。稍微重写了代码..仍然有同样的错误。想法? (另外..这个编辑垃圾越来越大..在 stackoverflow 中是否有一些首选方法来进行这些大的更新/编辑?

代码:

 77     def listen(self):
 78         # Create our socket stream to listen on.
 79         serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 80
 81         #serv.settimeout(5)
 82         serv.setblocking(0)
 83
 84         # Bind the address.
 85         serv.bind(('', self.PORT))
 86         serv.listen(5)
 87         self.serv = serv
 88
 89     def accept(self):
 90         (newsock, newaddr) = self.serv.accept()

调用代码:

 57     con.listen()
 58     pydbgp_proc = subprocess.Popen(
 59         ('pydbgp.py', '-d', 'localhost:%i' % OPTIONS['pydbgp_port'],
 60         OPTIONS['debug_file']),
 61         stdout=subprocess.PIPE,
 62         stderr=subprocess.PIPE,)
 63     con.accept()

错误:

       File "/home/lee/projects/vim-debug/repo/vimbug/dbgp.py", line 90, in accept
    (newsock, newaddr) = self.serv.accept()
  File "/usr/lib/python2.6/socket.py", line 197, in accept
    sock, addr = self._sock.accept()
error: [Errno 11] Resource temporarily unavailable

想法?

编辑 5: 我将接受函数更改为以下 select() 实现,这导致 'Not ready..?'正在打印。

 89     def accept(self):
 90         rfds, wfds, xfds = select.select([self.serv], [], [], 1)
 91
 92         if self.serv in rfds:
 93             print 'Read ready..?'
 94             (newsock, newaddr) = self.serv.accept()
 95         else:
 96             print 'Not ready..?'

最佳答案

您是否在监听代码中设置了 socket.setblocking(0)

生成监听服务器后,您应该能够通过 select() 调用读取状态...对我来说在 debian lenny 和 python 2.5 下运行良好的示例...

import socket
import select

SERVER_SOCKADDR = ("", 424242)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)      # <------------------
server.bind(SERVER_SOCKADDR)
server.listen(5)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setblocking(0)

result = client.connect_ex(SERVER_SOCKADDR)

rfds, wfds, xfds = select.select([server], [client], [], 1)
if server in rfds:
    print "Server socket: accept does not block"
    sockfd, addr = server.accept()    # sockfd.send() and sockfd.recv() to 
                                      # write and read the stream...
    sockfd.setblocking(0)
    print sockfd, addr
else:
    print "Server socket: accept blocks"
if client in wfds:
    print "Client socket: write does not block"
else:
    print "Client socket: write blocks"


server.close()
client.close()

当我运行那个...

[mpenning@Bucksnort ~]$ python socket_test.py
Server socket: accept does not block
<socket._socketobject object at 0xb75764c4> ('127.0.0.1', 35810)
Client socket: write does not block
[mpenning@Bucksnort ~]$

关于python - 如何启动连接到您正在监听的套接字的进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5697426/

相关文章:

c - 如何使用小缓冲区将格式化字符串发送到套接字?

javascript - 如何从使用 javascript 生成的工具提示中抓取文本

python - 从模块或类内部启动多处理,而不是从 main() 启动

c - Linux,了解用于网络扩展的 setsockopt() PACKET_FANOUT

php - 将图像从linux(使用不带curl的c)发布到php服务器

php - 如何判断套接字是否在 PHP 中打开?

python - 用于近似积分的自定义函数的未知错误

python - 使用 python 从 Windows 商店访问特定证书

python - 语法错误 : (unicode error) 'unicodeescape' codec can't decode bytes in position 12-13: malformed\N character escape

c# - 对 .Net 任务进行排序