2013-06-27 97 views
0

我想要2个进程在给定端口上进行通信,而没有任何一个具有定义的客户机或服务器角色。任一个进程都可以单独运行。任何时候都可以按任何顺序停止并重新启动。当它们都在运行时,它们需要进行通信(当只有一个正在运行时,通信就被丢弃)。Python - 连接套接字,客户机/服务器不可知的

我想要非阻塞套接字和Windows/Linux支持。

+0

该代码看起来不像Python。你的意思是那是伪代码吗? –

+0

这是非常粗糙的伪代码...... –

+0

好吧,所以我想对这个问题进行倒票,这里是为什么:A.)它甚至不是一个问题。 B.)你显然甚至没有试图为自己找到答案(或者,你使用谷歌很可怕,这是令人感到羞耻和纠正的)C.)实际上问题的问题并不是真正的问题(就像他们是字面的问题,但他们缺乏“我无法弄清楚这一点 - 或者我试图做X为什么不能我”)。请不要将这种批评视为残忍或虐待性的惩罚。 - 对任何拼写错误和任何错误都有帮助。 – 2013-06-27 01:45:03

回答

1

这是一个相当粗糙的类,实际上在某种程度上起作用,这可能会让你开始。

这里的主要技巧是不打扰listen:这些是纯对等连接,由< local-addr,remote-addr >对完全指定。

请注意,套接字处于非阻塞模式。我遇到了recv异常,但也可能有一个send(另外,发送给死亡对等者时发生断管错误等)。您还需要处理从EOF终止对等(当recv返回''而不是与EAGAIN失败)。

import errno 
import os 
import select 
import socket 

class Peer(object): 
    def __init__(self, local_addr, peer_addr): 
     self._local_addr = local_addr 
     self._peer_addr = peer_addr 
     self._renew() 
     self.reopen() 

    def _renew(self): 
     self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self._sock.bind(self._local_addr) 
     self._sock.setblocking(False) 
     self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     self._state = 'bound' 

    def is_open(self): 
     return self._state == 'open' 

    def is_opening(self): 
     return self._state == 'opening' 

    def reopen(self): 
     if self._state == 'open': 
      raise ValueError('already open') 
     if self._state == 'opening': 
      raise ValueError('open in progress') 
     print 'try connect to:', self._peer_addr 
     error = self._sock.connect_ex(self._peer_addr) 
     print 'result:', error 
     if error == 0: 
      self._state = 'open' 
      print 'connected immediately' 
     elif error in (errno.EINPROGRESS, errno.EINTR): 
      self._state = 'opening' 
      print 'connection in progress' 
     else: 
      raise socket.error(error, os.strerror(error)) 

    def _check_open(self): 
     if self._state != 'opening': 
      raise ValueError('improper call to _check_open') 
     print 'check connect to:', self._peer_addr 
     _, wfds, _ = select.select([], [self._sock], []) 
     if len(wfds) == 0: 
      # connection still in progress 
      return 
     # we have a result: fail or succeed, either way a result 
     try: 
      peer = self._sock.getpeername() 
     except socket.error as err: 
      print 'caught err:', err 
      if err.errno == errno.ENOTCONN: 
       print 'connection failed, no peer available' 
       self.close() 
       return 
      raise 
     print 'got a peer:', peer 
     self._state = 'open' 
     print 'connection finished' 

    def close(self): 
     if self._state in ('open', 'opening'): 
      self._sock.close() 
      self._renew() 
      # self.reopen() - or leave to caller 

    def send_if_connected(self, data): 
     # to do: add check for send to dead peer, and if so, _renew etc 
     if self._state == 'bound': 
      self.reopen() 
     if self._state == 'opening': 
      self._check_open() 
     if self._state == 'open': 
      self._sock.send(data) 

    def recv_if_connected(self): 
     # to do: add check for send to dead peer, and if so, _renew etc 
     if self._state == 'bound': 
      self.reopen() 
     if self._state == 'opening': 
      self._check_open() 
     if self._state == 'open': 
      try: 
       return self._sock.recv(1024) 
      except socket.error as err: 
       # still connected but no data avail 
       if err.errno == errno.EAGAIN: 
        return '' 
       raise 
     else: 
      return None 

if __name__ == '__main__': 
    import argparse 
    import time 

    parser = argparse.ArgumentParser(description='test Peer()') 
    parser.add_argument('-l', '--localhost', default='') 
    parser.add_argument('-p', '--port', type=int, default=9001) 
    parser.add_argument('-R', '--remote-host', default='') 
    parser.add_argument('-r', '--remote-port', type=int, default=9002) 
    args = parser.parse_args() 

    x = Peer((args.localhost, args.port), (args.remote_host, args.remote_port)) 
    for i in range(1, 10): 
     print 'attempt to send %d' % i 
     x.send_if_connected('send %d' % i) 
     got = x.recv_if_connected() 
     if got is not None: 
      print 'got: "%s"' % got 
     time.sleep(1) 

例如运行于:$ python peerish.py -p 9001 -r 9002 & python peerish.py -p 9002 -r 9001 &

+0

这有同步问题:如果两个connect()尝试做几乎没有在同一时间开火,同伴没有正确连接。不知道如何解决这个问题,而不是诉诸于实际的侦听器套接字。 – torek

相关问题