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

时间:2011-04-18 00:25:06

标签: 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..?'

3 个答案:

答案 0 :(得分:1)

Doug Hellman的Python Module of the Week是一个很好的地方,可以找到模块基本用法的介绍,例如subprocess

如果做不到这一点,导致问题的一些代码将帮助我们回答您的问题。

答案 1 :(得分:1)

您是否在监听代码中设置了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 ~]$

答案 2 :(得分:0)

有很多方法可以解决这个问题。最简单的是子进程在连接之前等待几秒钟。

目前还不清楚为什么要这样做,你能否填写我们的目标?