Python 如何启动连接到您的套接字的进程';你在听吗?
我有一个进程,我的代码是从Python 如何启动连接到您的套接字的进程';你在听吗?,python,multithreading,sockets,tcp,Python,Multithreading,Sockets,Tcp,我有一个进程,我的代码是从subprocess.Popen()启动的,它试图连接到我的代码也在侦听的套接字。问题是,如果代码首先开始侦听此套接字,则无法启动子进程。它被sock.accept()阻止,当sock.accept()超时时,当运行subprocess.Popen()时,它显然没有侦听。如果代码首先启动子进程,它将尝试连接到套接字,但在任何代码能够侦听它之前失败 现在。。我该怎么做呢?似乎我需要以非阻塞方式开始侦听,然后启动进程,但我有点困惑,因为即使我使用select()来处理队列,
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中有没有更好的方法来进行这些大的更新/编辑
代码:
呼叫代码:
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:我将accept函数更改为以下select()
实现,导致打印'notready..'
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()
calls读取状态……示例在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()
导入套接字
导入选择
服务器_SOCKADDR=(“”,424242)
服务器=socket.socket(socket.AF\u INET,socket.SOCK\u流)
server.setblocking(0)#您能否发布有关如何生成套接字以及子进程如何尝试连接到套接字的代码?当您删除(self.\u sock,remote\u address)=serv.accept()
并替换为pass
?@Lee,在上面的编辑5中,当您看到“未准备就绪”时,会发生什么情况…您是否已经尝试连接到客户端?您需要先连接一个客户端,然后才能在rfds
@中成功看到您的服务器。Mike,我不清楚我们的平台差异是什么?我正在运行Ubuntu服务器x64。(虽然,它在我的windows计算机上是一个VBox。。但这应该无关紧要)啊哈,服务器出现了一个错误,在我的一些测试中,我通过读取子进程中的io来阻止代码。我不知道为什么它会被永久阻止,但现在这有点无关紧要。关键是,我有一个成功的连接!我将修复我的代码,并为未来的谷歌发布一个最终的编辑工作代码。谢谢!子进程s是一个符合Xcode规范的调试服务器。因此,我的IDE实际上正在创建调试会话的实例。它需要开始侦听,以便调试服务器可以连接。我还认为计时器是最简单的解决方案,但它似乎缺少。如果可能的话,我更喜欢更干净、更优雅的东西。我可以重试直到它连接到了。是的,但那会假设你对调试服务器有控制权,而你没有。我不确定Xcode规范是否说服务器应该重试X次。这肯定是我应该添加的功能。好吧,看来你的客户端套接字不会立即失败,所以我要重写我的来监听(不要使用sock.accept()
),然后在启动子流程后读取结果?如果这是正确的用法,我就误解了sock.accept()
的作用。我认为这是数据实际被存取的地方
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 ~]$