This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: create_datagram_endpoint does not receive when both local_addr and remote_addr provided
Type: behavior Stage:
Components: asyncio Versions: Python 3.4, Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: ariddell, gvanrossum, vstinner, yselivanov
Priority: normal Keywords:

Created on 2014-06-10 00:38 by ariddell, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
client_bad.py ariddell, 2014-06-10 00:42 code to reproduce
Messages (4)
msg220134 - (view) Author: Allen Riddell (ariddell) Date: 2014-06-10 00:38
Creating a UDP connection through ``create_datagram_endpoint`` when specifying both remote_addr and local_addr does not work; messages are not received. If remote_addr is removed, messages are received.

Easy to reproduce:

works: python3 client_good.py & python3 sender.py 127.0.0.1 8888
blocks?: python3 client_bad.py & python3 sender.py 127.0.0.1 8888

From the PEP I gather this really is a bug, since create_datagram_endpoint is supposed to be bidirectional::

    create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, <options>). Creates an endpoint for sending and receiving datagrams (typically UDP packets). Because of the nature of datagram traffic, there are no separate calls to set up client and server side, since usually a single endpoint acts as both client and server.
msg220135 - (view) Author: Allen Riddell (ariddell) Date: 2014-06-10 00:42
(couldn't figure out how to attach multiple files)
-- client_good.py --

"""Send and receive a messages using DatagramProtocol"""
import asyncio
import time

class Helloer(asyncio.DatagramProtocol):

    def connection_made(self, transport):
        print('(helloer) connection made')
        self.transport = transport

    def connection_lost(self, transport):
        print('(helloer listener) connection lost!')

    def datagram_received(self, data, addr):
        print('(helloer listener) received data from {}: {}'.format(addr, data))

    def error_received(self, exc):
        print('(helloer listener) error received: {}'.format(exc))

loop = asyncio.get_event_loop()
# WORKS:
coro = loop.create_datagram_endpoint(Helloer, local_addr=('127.0.0.1', 8888))
# FAILS (blocks?):
# coro = loop.create_datagram_endpoint(Helloer, local_addr=('127.0.0.1', 8888), remote_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(coro)
loop.run_forever()


-- client_bad.py --

"""Send and receive a messages using DatagramProtocol"""
import asyncio
import time

class Helloer(asyncio.DatagramProtocol):

    def connection_made(self, transport):
        print('(helloer) connection made')
        self.transport = transport

    def connection_lost(self, transport):
        print('(helloer listener) connection lost!')

    def datagram_received(self, data, addr):
        print('(helloer listener) received data from {}: {}'.format(addr, data))

    def error_received(self, exc):
        print('(helloer listener) error received: {}'.format(exc))

loop = asyncio.get_event_loop()
# WORKS:
# coro = loop.create_datagram_endpoint(Helloer, local_addr=('127.0.0.1', 8888))
# FAILS (blocks?):
coro = loop.create_datagram_endpoint(Helloer, local_addr=('127.0.0.1', 8888), remote_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(coro)
loop.run_forever()


-- sender.py --
"""Send a UDP packet to a specified port and quit"""
import argparse
import socket
import time

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='send a udp packet')
    parser.add_argument('host', type=str)
    parser.add_argument('port', type=int)
    args = parser.parse_args()
    host, port = args.host, args.port

    time.sleep(0.1)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    data = 'message from sender sent to {}:{}'.format(host, port)
    sent = sock.sendto(data.encode('ascii'), (host, port))
    print("(sender) sent udp packet to {}:{}".format(host, port))
    sock.close()
msg220136 - (view) Author: Allen Riddell (ariddell) Date: 2014-06-10 01:02
I gather this is the desired behavior.

If one specifies remote_addr then one only accepts packets from that address and port. Whereas if no remote_addr is given then one accepts packets from any address and any port.

Sorry for the noise.
msg220148 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2014-06-10 07:35
I opened the issue #21702 to document the parameter remote_addr.
History
Date User Action Args
2022-04-11 14:58:04adminsetgithub: 65900
2014-06-10 07:35:53vstinnersetmessages: + msg220148
2014-06-10 01:02:52ariddellsetstatus: open -> closed
resolution: not a bug
messages: + msg220136
2014-06-10 00:42:27ariddellsetfiles: + client_bad.py

messages: + msg220135
2014-06-10 00:38:56ariddellcreate