python - How can I close a DatagramTransport as soon one datagram is sent? -


i'm trying close transport right after sending udp packet , i'm getting exception in callback _selectordatagramtransport._read_ready()

import asyncio   class myprotocol:     def __init__(self, message, loop):         self.message = message         self.loop = loop         self.transport = none      def connection_made(self, transport):         self.transport = transport         print("send:", self.message)         self.transport.sendto(self.message.encode())         self.transport.close()  # <----------      def error_received(self, exc):         print('error received', exc)      def connection_lost(self, exc):         print("socket closed, stop event loop")         self.loop.stop()  loop = asyncio.get_event_loop() message = "hello" connect = loop.create_datagram_endpoint(lambda: myprotocol(message, loop), remote_addr=('127.0.0.1', 2222)) transport, protocol = loop.run_until_complete(connect)  loop.run_forever() 

the full stack trace while running snippet above in cpython 3.5.1 is:

socket closed, stop event loop exception in callback _selectordatagramtransport._read_ready() handle: <handle _selectordatagramtransport._read_ready()> traceback (most recent call last):   file "/home/ecerulm/.pyenv/versions/3.5.1/lib/python3.5/asyncio/selector_events.py", line 1002, in _read_ready     data, addr = self._sock.recvfrom(self.max_size) attributeerror: 'nonetype' object has no attribute 'recvfrom'  during handling of above exception, exception occurred:  traceback (most recent call last):   file "/home/ecerulm/.pyenv/versions/3.5.1/lib/python3.5/asyncio/events.py", line 125, in _run     self._callback(*self._args)   file "/home/ecerulm/.pyenv/versions/3.5.1/lib/python3.5/asyncio/selector_events.py", line 1008, in _read_ready     self._fatal_error(exc, 'fatal read error on datagram transport')   file "/home/ecerulm/.pyenv/versions/3.5.1/lib/python3.5/asyncio/selector_events.py", line 587, in _fatal_error     self._loop.call_exception_handler({ attributeerror: 'nonetype' object has no attribute 'call_exception_handler' 

i believe exception generated if udp packet actively refused, icmp destination unreachable (which i'm not interested in).

so question right way of doing this. i'm not interested in connection anymore after sending want rid of transport possible. documentation datagramtransport.sendto() says methods doesn't block. how know when sending completed? (and complete mean when handed on os, not delivered remote).

is there other asyncio coroutine send udp packet asynchronously , simple await (maybe skipping whole create_datagram_endpoint) ?

is there other asyncio coroutine send udp packet asynchronously , simple await?

i would, base on datagramtransport source, wrap in future yieldable/awaitable. raise exception on error , return true on success. example poc code:

import asyncio import socket  class udpclient():      def __init__(self, host, port, loop=none):         self._loop = asyncio.get_event_loop() if loop none else loop         self._sock = socket.socket(socket.af_inet, socket.sock_dgram)         self._sock.setblocking(false)         self._addr = (host, port)         self._future = none         self._data = none      def sendto(self, data):         self._future = asyncio.future(loop=self._loop)         self.data = data if isinstance(data, bytes) else str(data).encode('utf-8')         loop.add_writer(self._sock.fileno(), self._sendto)         return self._future      def _sendto(self):         try:             self._sock.sendto(self.data, self._addr)         except (blockingioerror, interruptederror):             return         except oserror exc:             self.abort(exc)         except exception exc:             self.abort(exc)         else:             self.close()             self._future.set_result(true)      def abort(self, exc):         self.close()         self._future.set_exception(exc)      def close(self):         self._loop.remove_writer(self._sock.fileno())         self._sock.close() 

than simple example like:

@asyncio.coroutine def test():     yield udpclient('127.0.0.1', 1234).sendto('ok')  # or 3.5+ syntax # async def test(): #     await udpclient('127.0.0.1', 1234).sendto('ok')   loop = asyncio.get_event_loop() loop.run_until_complete(test()) 

Comments

Popular posts from this blog

gridview - Yii2 DataPorivider $totalSum for a column -

java - Suppress Jboss version details from HTTP error response -

Sass watch command compiles .scss files before full sftp upload -