Hundemeier / sacn

A simple ANSI E1.31 (aka sACN) module for python.
MIT License
47 stars 21 forks source link

Closing the connection incomplete `Address already in use` #38

Closed constant-flow closed 3 years ago

constant-flow commented 3 years ago

First of all, thx for this great lib, works great. Unfortunately, closing seems to miss something as the Address already in use kicks in, when I restart the connection.

I simply used the example and tried to run it twice

Repro

import sacn
import time

# provide an IP-Address to bind to if you are using Windows and want to use multicast
sender = sacn.sACNsender()
sender.start()  # start the sending thread
sender.activate_output(1)  # start sending out data in the 1st universe
sender[1].multicast = True  # set multicast to True
# sender[1].destination = "192.168.1.20"  # or provide unicast information.
# Keep in mind that if multicast is on, unicast is not used
sender[1].dmx_data = (1, 2, 3, 4)  # some test DMX data

time.sleep(3)  # send the data for 10 seconds
sender.stop()  # do not forget to stop the sender

#####################
# AND AGAIN

# provide an IP-Address to bind to if you are using Windows and want to use multicast
sender = sacn.sACNsender()
sender.start()  # start the sending thread
sender.activate_output(1)  # start sending out data in the 1st universe
sender[1].multicast = True  # set multicast to True
# sender[1].destination = "192.168.1.20"  # or provide unicast information.
# Keep in mind that if multicast is on, unicast is not used
sender[1].dmx_data = (1, 2, 3, 4)  # some test DMX data

time.sleep(3)  # send the data for 10 seconds
sender.stop()  # do not forget to stop the sender

results in

❯ python3 sacn-test.py
Traceback (most recent call last):
  File "sacn-test.py", line 17, in <module>
    sender = sacn.sACNsender()
  File "/Users/.../lib/python3.7/site-packages/sacn/sender.py", line 43, in __init__
    self._sender_handler = SenderHandler(cid, source_name, self._outputs, bind_address, bind_port, fps, socket)
  File "/Users/.../lib/python3.7/site-packages/sacn/sending/sender_handler.py", line 23, in __init__
    self.socket: SenderSocketBase = SenderSocketUDP(self, bind_address, bind_port, fps)
  File "/Users/.../lib/python3.7/site-packages/sacn/sending/sender_socket_udp.py", line 35, in __init__
    self._socket.bind((self._bind_address, self._bind_port))
OSError: [Errno 48] Address already in use
Exception ignored in: <function sACNsender.__del__ at 0x7fa1f03597b8>
Traceback (most recent call last):
  File "/Users/.../lib/python3.7/site-packages/sacn/sender.py", line 157, in __del__
    self.stop()
  File "/Users/.../lib/python3.7/site-packages/sacn/sender.py", line 153, in stop
    self._sender_handler.stop()
AttributeError: 'sACNsender' object has no attribute '_sender_handler'
Hundemeier commented 3 years ago

Unfortunately, I can not reproduce this issue with your code on Win10 20H2 or Debian 11 (Kernel 5.10.0). This should actually work, but some platforms do not allow the reuse of ports. Sometimes this works with simply waiting a bit between stopping and creating a new sender. (What should be working is to use one sender instance and start and stop it as needed, as this does not create a new UDP socket).

Does the following code work (i.e. does nothing) on your platform or does it throw an execption?

tmp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tmp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
constant-flow commented 3 years ago

I tested on Mac OS Big Sur 11.4 The two lines you suggest don't throw an exception.

I also tested without recalling the constructor, also this works.

Calling the destructor for sender didn't help

Hundemeier commented 3 years ago

Could you check if the behavior changes with version v1.8.1?

I also tested without recalling the constructor, also this works.

I guess you mean calling stop() and then start() afterwards? This should no longer work in v1.8.1.

constant-flow commented 3 years ago

Thx for the fix. Calling stop() then start() works now without an exception (v1.8.1) .

Concerning the destructor: This was another thing i just tested if it would help to shut down the socket ... in fact it didn't help (typo on my end).

Keep up the good work.