我想要2个进程在给定端口上进行通信,而没有任何一个具有定义的客户机或服务器角色。任一个进程都可以单独运行。任何时候都可以按任何顺序停止并重新启动。当它们都在运行时,它们需要进行通信(当只有一个正在运行时,通信就被丢弃)。Python - 连接套接字,客户机/服务器不可知的
我想要非阻塞套接字和Windows/Linux支持。
我想要2个进程在给定端口上进行通信,而没有任何一个具有定义的客户机或服务器角色。任一个进程都可以单独运行。任何时候都可以按任何顺序停止并重新启动。当它们都在运行时,它们需要进行通信(当只有一个正在运行时,通信就被丢弃)。Python - 连接套接字,客户机/服务器不可知的
我想要非阻塞套接字和Windows/Linux支持。
这是一个相当粗糙的类,实际上在某种程度上起作用,这可能会让你开始。
这里的主要技巧是不打扰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 &
。
这有同步问题:如果两个connect()尝试做几乎没有在同一时间开火,同伴没有正确连接。不知道如何解决这个问题,而不是诉诸于实际的侦听器套接字。 – torek
该代码看起来不像Python。你的意思是那是伪代码吗? –
这是非常粗糙的伪代码...... –
好吧,所以我想对这个问题进行倒票,这里是为什么:A.)它甚至不是一个问题。 B.)你显然甚至没有试图为自己找到答案(或者,你使用谷歌很可怕,这是令人感到羞耻和纠正的)C.)实际上问题的问题并不是真正的问题(就像他们是字面的问题,但他们缺乏“我无法弄清楚这一点 - 或者我试图做X为什么不能我”)。请不要将这种批评视为残忍或虐待性的惩罚。 - 对任何拼写错误和任何错误都有帮助。 – 2013-06-27 01:45:03