Golang net.Listen binds to port thats already in use

2024/10/14 7:20:48

Port 8888 is already bound on my (OS X 10.13.5) system, by a process running inside a docker container:

$ netstat -an | grep 8888
tcp6       0      0  ::1.8888               *.*                    LISTEN
tcp4       0      0  *.8888                 *.*                    LISTEN

A python program which tries to bind to that port (using as close to the socket options of golang as I can manage), fails in the way I expect:

import socket
import fcntl
import osdef main():sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)flag = fcntl.fcntl(sock.fileno(), fcntl.F_GETFL)fcntl.fcntl(sock.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)sock.bind(("0.0.0.0", 8888))sock.listen(5)main()

fails with:

$ python test.py
Traceback (most recent call last):File "test.py", line 15, in <module>main()File "test.py", line 11, in mainsock.bind(("0.0.0.0", 8888))
OSError: [Errno 48] Address already in use

But a go program creating a connection via net.Listen does not fail, as I expect it to:

package mainimport ("fmt""net"
)func main() {_, err := net.Listen("tcp", "0.0.0.0:8888")if err != nil {fmt.Printf("Connection error: %s\n", err)} else {fmt.Println("Listening")}
}

Succeeds with:

$ go run test.go
Listening

A coworker reports that with the same setup, his Ubuntu system correctly fails the go program.

Why does this succeed on a Mac, and how can I get the net.Listen to show an error in binding to port 8888?

edit: If I occupy port 8888 with a simple go program like:

package mainimport ("log""net/http"
)func main() {log.Fatal(http.ListenAndServe("0.0.0.0:8888", nil))
}

Then test.go correctly fails to bind to the port. However the docker process (which is running basically that ^^^) does not cause it to fail.

edit 2: If I specify "tcp4", then the program does indeed fail as I expect. If I specify "tcp6", it succeeds but netstat says it binds to * instead of ::1:

$ netstat -an | grep 8888
tcp6       0      0  *.8888                 *.*                    LISTEN
tcp6       0      0  ::1.8888               *.*                    LISTEN
tcp4       0      0  *.8888                 *.*                    LISTEN

So, specifying "tcp4" will solve my actual problem, but I really want to understand what the heck is going on with the "tcp46" connection type, and I can't find any documentation. Help!

Answer

OK, I think I have a story to tell about why this happens:

  1. Docker on mac, when mapping a port, binds to IPv4 0.0.0.0:<port> and IPv6 [::1]:<port>. Note that on IPv6 it maps to the equivalent of localhost rather than 0.0.0.0, which would be [::]!
  2. Golang, when opening a socket to listen on, by default opens an IPv6 socket that is mapped in some way to also listen to IPv4. (I still don't completely understand this tcp46 type, so if you have good docs please point me to them!).
  3. So my golang program was opening an IPv6 socket on [::]:8888, the equivalent of 0.0.0.0:8888 in IPv6. This succeeded because docker was listening on [::1] (the equivalent of 127.0.0.1), not [::]
  4. That's it! So the golang program succeeded even though it will only get connected to by a client connecting on IPv6 from a non-loopback address (I think, I got too tired to test this, give me a break)

My coworker reports that on Ubuntu, docker listens on [::], which is why he was unable to reproduce the problem I was seeing. This seems like the sensible behavior! And I have no idea why it doesn't do so on mac.

I also think it's surprising and possibly a bit wrong that Go happily succeeds in this instance, even though it's creating a socket that's very difficult to actually access? But I can't say that it's definitely a bug, and I definitely don't feel like trying to report it as such to the go project.

https://en.xdnf.cn/q/69442.html

Related Q&A

Aiohttp, Asyncio: RuntimeError: Event loop is closed

I have two scripts, scraper.py and db_control.py. In scraper.py I have something like this: ... def scrape(category, field, pages, search, use_proxy, proxy_file):...loop = asyncio.get_event_loop()to_do…

Python for ios interpreter [duplicate]

This question already has answers here:Closed 11 years ago.Possible Duplicate:Python or Ruby Interpreter on iOS I just discovered this apps pypad and python for ios They have like an interpreter an ed…

Detect when multiprocessing queue is empty and closed

Lets say I have two processes: a reader and a writer. How does the writer detect when the reader has finished writing values?The multiprocessing module has a queue with a close method that seems custo…

imshow and histogram2d: cant get them to work

Im learning Python and this is my first question here. Ive read other topics related to the usage of imshow but didnt find anything useful. Sorry for my bad English.I have plotted a set of points here,…

3D Waterfall Plot with Colored Heights

Im trying to visualise a dataset in 3D which consists of a time series (along y) of x-z data, using Python and Matplotlib.Id like to create a plot like the one below (which was made in Python: http://a…

python xlsxwriter: Keep header in excel when adding a table

I have a panda dataframe that I write to a xslx file, and would like to add a table over that data. I would also like to keep the headers that I have already written, instead of adding them again. Is t…

Unexpected tokens in !DOCTYPE html in PyCharm Community Edition

I am new in using PyCharm but I am loving it gradually. I am getting a red underline on <!DOCTYPE html> and the error is "Unexpected Token".Why PyCharm shows it? I cant understand.

Indexing a numpy array with a numpy array of indexes [duplicate]

This question already has answers here:Indexing a numpy array with a list of tuples(2 answers)Index multidimensional array with index array(1 answer)Closed 5 years ago.I have a 3D numpy array data and …

Input redirection with python

I have the following program to test input redirection in Python.a = int(raw_input("Enter a number: ")) b = raw_input("Enter a string: ") print "number entered = ", a prin…

TypeError: can only concatenate str (not numpy.int64) to str

I want to print the variable based on the index number based on the following dataset:Here I used the following code:import pandas as pdairline = pd.read_csv("AIR-LINE.csv")pnr = input("…