简体   繁体   中英

How do I not destroy an UDP port when binding a socket?

I am using GCDAsyncUdpSocket to open an UDP socket and then I bind it to a port. The class is just a wrapper around the usual POSIX socket calls like socket , bind , etc.

SCENARIO 1:

  • MyMacBook: start process A
  • MyMacBook: open UDP port 23141 => SUCCESS
  • SomeComputer: send an UDP packet to MyMacBook, port 23141
  • MyMacBook: the standard OSX firewall asks me if i want to allow incoming network connections, and I agree.
  • MyMacBook: ignore packet, don't read it. (or at least, i don't see a log message that tells me that i got a packet. either my code is broken, or the CocoaAsyncSocket code is broken, or the OS didn't report the packet to my program.)
  • MyMacBook: kill process A
  • MyMacBook: start process A
  • MyMacBook: open UDP port 23141 => FAIL: Error Domain=NSPOSIXErrorDomain Code=48 "Address already in use" UserInfo=0x100407f30 {NSLocalizedDescription=Address already in use, NSLocalizedFailureReason=Error in bind() function

Why???

netstat -n |grep 2314
udp4     626      0  *.23146                *.*                               
udp4    1251      0  *.23141                *.*

^^this is how a broken UDP port looks like on the shell. If I ever want to use that port number again, I seem to have to restart my machine :-(

And no, I don't have old processes hanging around that block the port. I checked with ps aux and with lsof -i | grep UDP lsof -i | grep UDP .

SCENARIO 2:

  • MyMacBook: start process A
  • MyMacBook: open UDP port 23143 => SUCCESS
  • MyMacBook: kill process A
  • MyMacBook: start process A
  • MyMacBook: open UDP port 23143 => SUCCESS
  • MyMacBook: kill process A
  • MyMacBook: start process A
  • MyMacBook: open UDP port 23143 => SUCCESS
  • MyMacBook: kill process A
  • ...

If the port is never used, the system doesn't care if I dont close it nicely. This is how it should be.

My question:

What is wrong here? Of course, in a perfect world, a program wouldn't crash, and sockets are all closed with the POSIX close function. In an imperfect world, I just type Cmd-. in XCode to kill the app I am developing, and close isn't called.

When I am trying to bind my socket to an UDP port, what I am really trying to say to the OS is this: "Please OSX 10.8.5, bind my socket to port 23141. If some other program has it opened currently and is listening, then you may tell me that the port is in use, but if no running program cares about this port, then let me bind it to port 23141!!" Is this an OSX bug? Is it new? Is it a documented known bug, or a so-called "feature"?

This seems to be a bug in OSX.

Related posts:
https://superuser.com/questions/504750/kill-udp-port-that-has-no-process
https://apple.stackexchange.com/questions/71300/how-can-i-unbind-a-udp-port-that-has-no-entry-in-lsof
(@Barmar: thanks for finding these articles)

1) I have noted, that if a UDP port is broken (it is bound, but not bound to a particular process), then you have to restart the computer to use this port again. Logging off, and logging in again doesn't work.

2) I found out, that there is no problem if you disable the OSX Firewall . This means that the problem is a bug in the standard OSX firewall. However, a broken port doen't get unbroken if you disable the firewall, you still have to restart your computer to unbreak it. But: if the firewall is off, no port becomes broken.

There is something we can learn from part 2: the OSX firewall is not a simple packet filter. It seems to hack the socket commands on a kernel level.

Maybe someone wants to write a bug report and send it to Apple... (sounds like a joke, doesn't it?)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM