Python-连接套接字,客户端/服务器无关
我想要两个进程在给定的端口上通信,其中一个没有定义的客户机或服务器角色。这两个进程中的任何一个都可能单独运行。任何一个都可以在任何时间以任何顺序停止和重新启动。当它们都在运行时,它们需要通信(当只有一个在运行时,通信被丢弃)Python-连接套接字,客户端/服务器无关,python,sockets,networking,Python,Sockets,Networking,我想要两个进程在给定的端口上通信,其中一个没有定义的客户机或服务器角色。这两个进程中的任何一个都可能单独运行。任何一个都可以在任何时间以任何顺序停止和重新启动。当它们都在运行时,它们需要通信(当只有一个在运行时,通信被丢弃) 我需要非阻塞套接字和Windows/Linux支持。这里有一个相当粗糙的类,它实际上在某种程度上可以工作,这可能会让您开始学习 这里的主要诀窍是根本不用理会listen:它们是完全由对指定的纯对等连接 请注意,插座处于非阻塞模式。我捕获了recv异常,但也可能有send异常
我需要非阻塞套接字和Windows/Linux支持。这里有一个相当粗糙的类,它实际上在某种程度上可以工作,这可能会让您开始学习 这里的主要诀窍是根本不用理会
listen
:它们是完全由对指定的纯对等连接
请注意,插座处于非阻塞模式。我捕获了recv
异常,但也可能有send
异常(另外,当发送到死掉的对等方时,会出现断管错误等)。您还需要处理来自终止对等方的EOF(当recv
返回'
而不是EAGAIN失败时)
例如,使用:$python peerish.py-p 9001-r 9002和python peerish.py-p 9002-r 9001&
运行。该代码看起来与python完全不同。你的意思是这是伪代码吗?这是非常粗糙的伪代码…好吧,所以我想否决这个问题,原因如下:A.)这甚至不是一个问题。B.)显然你甚至没有为自己找到答案(或者,你很讨厌使用谷歌,这是一件让人感到羞耻和需要纠正的事情)C.)实际上是问题的问题并不是真正的问题(就像是字面上的问题,但它们缺乏任何意义“我想不出来——或者我试过做X为什么我做不到。”)。请不要把这种批评视为残忍或施虐的惩罚。-为拼写错误和诸如此类的事情感到抱歉。你是对的,我只是在试图解决这个问题之前懒洋洋地写了这个问题,认为一定是其他人已经解决了。(在谷歌上找不到解决方案。)。无论如何,我现在已经发布了自己的解决方案。UDP(又名SOCK_DGRAM,而不是SOCK_STREAM)是否适用于此应用程序?只需在UDP端口(n)上处理a接收,在UDP端口(n+1)上处理B接收即可,并让每一个都发送到另一个的UDP端口。这将为您提供所需的大部分质量,以及打包;唯一的缺点是偶尔会丢失一个数据包(在本地主机上不常见,但并非不可能),因此您的应用程序必须对此进行说明。这与同步有关:如果两个连接()尝试不会在几乎相同的时间触发,对等点无法正确连接。除了求助于实际的侦听器套接字之外,不确定如何修复此问题。
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)