Как повторно подключить сокет на asyncio?
Я хотел бы создать два протокола (TcpClient и UdpServer) с asyncio on app.py где TcpClient будет иметь постоянное соединение с server.py и UdpServer, служащий сервером UDP:
что нужно:
a) что оба протокола для связи: вызов метода друг друга. Это работает только на первом соединении. Если TcpClient повторно подключиться, он не может отправить снова строку " отправить tcp."исходя из UdpServer. Я сверяюсь с print(self)
и TcpClient создать новый экземпляр, а старый до сих пор существует, но без связи, но я не знаю как refactory, что. Я думаю, что я использую asyncio неправильно.
b) когда TcpClient отключается от server.py, подождите 5s и попробуйте снова подключиться и так далее. Я попытался к этому используя call_later()
из asyncio, но я думаю, что есть родной способ сделать это, а не искусственность.
c) когда я начинаю app.py и если TcpClient не может подключиться, я хотел бы попытаться снова подключиться после 5s и так далее. Я не знаю, как это сделать.
вот мои примеры тестов app.py server.py - ... В server.py это просто для тестов-это будет другой язык.
просто сказать, что я пробовал:
1) Когда я начинаю app.py и server.py вниз, app.py не пытайтесь повторить.
2) Когда app.py подключены к server.py и сервер вниз и быстро вверх, TcpClient снова подключается, но я не могу больше подключать друг к другу методы на новом экземпляре и отправлять строку "отправить в tcp." к в server.py только старые, где нет больше связи.
3) Если я использую asyncio.async()
вместо run_until_complete()
Я не могу вызывать методы друг от друга протоколов.
Я положил app.py и server.py здесь, так что вы можете просто скопировать и запустить тесты.
Я использую ncat localhost 9000 -u -v
для отправки строки " отправить в tcp.". Эта строка должна быть напечатана в классе UdpServer и передана методу send_data_to_tcp в классе TcpClient, и этот метод будет отправлен в строку server.py - ...
Я использую Python 3.4.0.
большое спасибо.
app.py:
import asyncio
#TCP client
class TcpClient(asyncio.Protocol):
message = 'Testing'
def connection_made(self, transport):
self.transport = transport
self.transport.write(self.message.encode())
print('data sent: {}'.format(self.message))
server_udp[1].tcp_client_connected()
def data_received(self, data):
self.data = format(data.decode())
print('data received: {}'.format(data.decode()))
if self.data == 'Testing':
server_udp[1].send_data_to_udp(self.data)
def send_data_to_tcp(self, data):
self.transport.write(data.encode())
def connection_lost(self, exc):
msg = 'Connection lost with the server...'
info = self.transport.get_extra_info('peername')
server_udp[1].tcp_client_disconnected(msg, info)
#UDP Server
class UdpServer(asyncio.DatagramProtocol):
CLIENT_TCP_TIMEOUT = 5.0
def __init__(self):
self.client_tcp_timeout = None
def connection_made(self, transport):
print('start', transport)
self.transport = transport
def datagram_received(self, data, addr):
self.data = data.strip()
self.data = self.data.decode()
print('Data received:', self.data, addr)
if self.data == 'send to tcp.':
client_tcp[1].send_data_to_tcp(self.data)
def connection_lost(self, exc):
print('stop', exc)
def send_data_to_udp(self, data):
print('Receiving on UDPServer Class: ', (data))
def connect_client_tcp(self):
coro = loop.create_connection(TcpClient, 'localhost', 8000)
#client_tcp = loop.run_until_complete(coro)
client_tcp = asyncio.async(coro)
def tcp_client_disconnected(self, data, info):
print(data)
self.client_tcp_info = info
self.client_tcp_timeout = asyncio.get_event_loop().call_later(self.CLIENT_TCP_TIMEOUT, self.connect_client_tcp)
def tcp_client_connected(self):
if self.client_tcp_timeout:
self.client_tcp_timeout.cancel()
print('call_later cancel.')
loop = asyncio.get_event_loop()
#UDP Server
coro = loop.create_datagram_endpoint(UdpServer, local_addr=('localhost', 9000))
#server_udp = asyncio.Task(coro)
server_udp = loop.run_until_complete(coro)
#TCP client
coro = loop.create_connection(TcpClient, 'localhost', 8000)
#client_tcp = asyncio.async(coro)
client_tcp = loop.run_until_complete(coro)
loop.run_forever()
server.py:
import asyncio
class EchoServer(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('connection from {}'.format(peername))
self.transport = transport
def data_received(self, data):
print('data received: {}'.format(data.decode()))
self.transport.write(data)
# close the socket
#self.transport.close()
#def connection_lost(self):
# print('server closed the connection')
loop = asyncio.get_event_loop()
coro = loop.create_server(EchoServer, 'localhost', 8000)
server = loop.run_until_complete(coro)
print(server)
print(dir(server))
print(dir(server.sockets))
print('serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
print("exit")
finally:
server.close()
loop.close()
1 ответов
вам действительно нужно только несколько небольших исправлений. Во-первых, я написал корутину для обработки попыток подключения:
@asyncio.coroutine
def do_connect():
global tcp_server # Make sure we use the global tcp_server
while True:
try:
tcp_server = yield from loop.create_connection(TcpClient,
'localhost', 8000)
except OSError:
print("Server not up retrying in 5 seconds...")
yield from asyncio.sleep(5)
else:
break
затем мы используем это, чтобы запустить все:
loop = asyncio.get_event_loop()
#UDP Server
coro = loop.create_datagram_endpoint(UdpServer, local_addr=('localhost', 9000))
server_udp = loop.run_until_complete(coro)
#TCP client
loop.run_until_complete(do_connect())
loop.run_forever()
следующая часть обрабатывает сервер, идущий вниз / возвращающийся после app.py запускается. Мы должны исправить tcp_client_disconnected
и connect_client_tcp
чтобы справиться с этим должным образом:
def connect_client_tcp(self):
global client_tcp
task = asyncio.async(do_connect())
def cb(result):
client_tcp = result
task.add_done_callback(cb)
def tcp_client_disconnected(self, data, info):
print(data)
self.client_tcp_info = info
self.client_tcp_timeout = loop.call_later(self.CLIENT_TCP_TIMEOUT, self.connect_client_tcp)
интересная часть connect_client_tcp
. У тебя было две проблемы с оригиналом. версия:
вы назначали
client_tcp
непосредственно к результатуasyncio.async(coro)
, что означаетclient_tcp
была назначенаasyncio.Task
. Это было не то, чего ты хотела, ты хотела!--7--> присваивается результату завершенногоasyncio.Task
. Мы достигаем этого, используяtask.add_done_callback
присвоитьclient_tcp
в результатеTask
после ее завершения.вы забыли
global client_tcp
в верхней части метода. Без этого вы просто создаете локальная переменнаяclient_tcp
, который был выброшен в концеconnect_client_tcp
.
как только эти проблемы будут исправлены, я смогу запустить app.py
, start / stop serv.py
всякий раз, когда я хочу, но всегда видеть все сообщения правильно доставлены из ncat
to serv.py
когда все три компонента работают вместе.
вот app.py
, для легкого копирования/вставки:
import asyncio
#TCP client
class TcpClient(asyncio.Protocol):
message = 'Testing'
def connection_made(self, transport):
self.transport = transport
self.transport.write(self.message.encode())
print('data sent: {}'.format(self.message))
server_udp[1].tcp_client_connected()
def data_received(self, data):
self.data = format(data.decode())
print('data received: {}'.format(data.decode()))
if self.data == 'Testing':
server_udp[1].send_data_to_udp(self.data)
def send_data_to_tcp(self, data):
self.transport.write(data.encode())
def connection_lost(self, exc):
msg = 'Connection lost with the server...'
info = self.transport.get_extra_info('peername')
server_udp[1].tcp_client_disconnected(msg, info)
#UDP Server
class UdpServer(asyncio.DatagramProtocol):
CLIENT_TCP_TIMEOUT = 5.0
def __init__(self):
self.client_tcp_timeout = None
def connection_made(self, transport):
print('start', transport)
self.transport = transport
def datagram_received(self, data, addr):
self.data = data.strip()
self.data = self.data.decode()
print('Data received:', self.data, addr)
if self.data == 'send to tcp.':
client_tcp[1].send_data_to_tcp(self.data)
def connection_lost(self, exc):
print('stop', exc)
def send_data_to_udp(self, data):
print('Receiving on UDPServer Class: ', (data))
def connect_client_tcp(self):
global client_tcp
coro = loop.create_connection(TcpClient, 'localhost', 8000)
task = asyncio.async(do_connect())
def cb(result):
client_tcp = result
task.add_done_callback(cb)
def tcp_client_disconnected(self, data, info):
print(data)
self.client_tcp_info = info
self.client_tcp_timeout = loop.call_later(self.CLIENT_TCP_TIMEOUT, self.connect_client_tcp)
def tcp_client_connected(self):
if self.client_tcp_timeout:
self.client_tcp_timeout.cancel()
print('call_later cancel.')
@asyncio.coroutine
def do_connect():
global client_tcp
while True:
try:
client_tcp = yield from loop.create_connection(TcpClient, 'localhost', 8000)
except OSError:
print("Server not up retrying in 5 seconds...")
yield from asyncio.sleep(1)
else:
break
loop = asyncio.get_event_loop()
#UDP Server
coro = loop.create_datagram_endpoint(UdpServer, local_addr=('localhost', 9000))
server_udp = loop.run_until_complete(coro)
#TCP client
loop.run_until_complete(do_connect())
loop.run_forever()