Как запустить процесс, который подключается к сокету, который вы слушаете? - PullRequest
2 голосов
/ 18 апреля 2011

У меня есть процесс, который мой код запускает с subprocess.Popen(), который пытается подключиться к сокету, который мой код также прослушивает. Проблема в том, что если код начинает прослушивать этот сокет первым, он не может запустить подпроцесс. Он был заблокирован sock.accept(), и когда sock.accept() истекает, он явно не слушает, когда запускается subprocess.Popen(). Если код сначала запускает подпроцесс, он пытается подключиться к сокету, но затем терпит неудачу, прежде чем какой-либо код сможет его прослушать.

Теперь ... есть мысли о том, как я могу это сделать? Казалось бы, мне нужно начать слушать неблокирующим образом, а затем запустить процесс, но я немного сбит с толку, потому что даже если я использую select () для обработки очереди, в конце концов вызывается sock.accept () и таким образом блокирует код ... я думаю.

В любом случае, какое-то направление было бы очень удобно! Я бы предпочел не делать этого, но если это облегчает жизнь, мне тоже не суждено использовать Twisted.

Редактировать 1: Я попытаюсь что-то сделать с помощью кода, мне нужно взглянуть на мои старые коммиты, чтобы найти рабочую версию. Хотя в принципе я не думаю, что мой код - это проблема. Мне кажется, я просто неправильно это реализую.

Например, если я запускаю свой слушатель сокетов и вручную, в оболочке, запускаю этот подпроцесс.Popen () процесс, который он подключает просто отлично. Это потому что оболочка уже слушает. Я верю моя проблема - просто курица и яйцо. В моем коде, по одному пути кода, если я запускаю процесс первым, он мгновенно завершается сбоем, потому что сервер сокетов не прослушивает пока . Однако, если я сначала запускаю сервер сокетов, он отключается, потому что он блокируется, и никакой подпроцесс не запускается, пока он не завершит блокировку . Мое решение, я полагаю, заключается в неблокирующем коде, но я очень не знаю, как этого добиться правильно. Я вижу много упоминаний о 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: Хорошо. Немного переписал код .. всё равно ошибка та же. Мысли? (Также .. этот мусор редактирования становится большим .. есть ли какой-нибудь предпочтительный способ в стеке потока делать эти большие обновления / правки?

Код:

 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 ]

1 голос
/ 18 апреля 2011

Python-модуль недели Дуга Хеллмана - хорошее место, чтобы найти введение в базовое использование модуля, такое как подпроцесс .

.вызывает проблемы поможет нам ответить на ваш вопрос.

1 голос
/ 18 апреля 2011

Вы устанавливаете 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 ~]$
0 голосов
/ 18 апреля 2011

Есть несколько способов приблизиться к этому. Самое простое - подпроцесс подождет несколько секунд перед подключением.

Непонятно, почему вы это делаете, можете ли вы рассказать нам о своей цели?

...