79

My server software says errno99: cannot assign requested address while using an ip address other than 127.0.0.1 for binding.

But if the IP address is 127.0.0.1 it works. Is it related to namespaces?

I am executing my server and client codes in another python program by calling execfile(). I am actually editing the mininet source code.I edited net.py and inside that I used execfile('server.py') execfile('client1.py') and execfile('client2.py').So as soon as "sudo mn --topo single,3" is called along with the creation of 3 hosts my server and client codes will get executed.I have given my server and client codes below.

#server code
import select 
import socket 
import sys 
backlog = 5 
size = 1024 
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
server.bind(("10.0.0.1",9999)) 
server.listen(backlog) 
input = [server] 
running = 1 
while running: 
    inputready,outputready,exceptready = select.select(input,[],[]) 
    for s in inputready: 
        if s == server: 
            client, address = server.accept() 
            input.append(client)
        else: 
            l = s.recv(1024)
            sys.stdout.write(l)
server.close()


#client code
import socket
import select
import sys
import time
while(1) :
    s,addr=server1.accept()    
    data=int(s.recv(4))
    s = socket.socket()
    s.connect(("10.0.0.1",9999))
    while (1):
        f=open ("hello1.txt", "rb")
        l = f.read(1024)
        s.send(l)
        l = f.read(1024)
        time.sleep(5)
s.close()
Torxed
  • 22,866
  • 14
  • 82
  • 131
user2833462
  • 805
  • 1
  • 7
  • 6
  • Show us some code, or we can't help you. (preferably how you setup the socket, and how you execute the "server" by calling `execfile()` (any reason for using `execfile()` btw?)) – Torxed Oct 08 '13 at 11:16
  • 1
    Which address are you using when you try something else than 127.0.0.1? I reproduced your error with binding to some invalid IP. Remember a server can only bind on itself, so the IP or the name you give must be one of the server... – mguijarr Oct 08 '13 at 13:57
  • 1
    When you bind(), you are associating the socket with a local IP address and a port. So, as long as the address is local, 127.0.0.1 (localhost address) included, bind would work. But, trying to bind to a address that is not local would lead to the above error. – Manoj Pandey Oct 09 '13 at 06:09
  • @Torxed I have edited the question.Please go through that. – user2833462 Oct 09 '13 at 06:26
  • @ManojPandey Thanks a lot.But how can I make it work?How can I make address local? – user2833462 Oct 09 '13 at 06:54
  • 1
    @user2833462 `10.x.x.x`, `172.16.x.x`, `192.168.x.x` or `127.0.0.x` are local networks. But that sad, `83.127.224.44` is a local *address* (and it's a local *address* you want to bind to) because it's the address assigned to your computer. (ie- You wouldn't be able to `bind()` to "www.google.com" because you don't own it, but if you own "www.made-up-example.com" you would be able to bind to that address, and once you understand that basic concept you would need to bind to made-up-example.com's *IP* and not the address itself). – Torxed Oct 09 '13 at 09:05
  • You could just pass an empty string as address and that would bind for all local addresses: "server.bind(("",6677)) ". With this, it would start to receive packets destined for any address on this box as long as they are destined for port 6677! – Manoj Pandey Oct 09 '13 at 19:09

7 Answers7

66

Stripping things down to basics this is what you would want to test with:

import socket
server = socket.socket() 
server.bind(("10.0.0.1", 6677)) 
server.listen(4) 
client_socket, client_address = server.accept()
print(client_address, "has connected")
while True:
    recvieved_data = client_socket.recv(1024)
    print(recvieved_data)

This works assuming a few things:

  1. Your local IP address (on the server) is 10.0.0.1 (This video shows you how)
  2. No other software is listening on port 6677

Also note the basic concept of IP addresses:

Try the following, open the start menu, in the "search" field type cmd and press enter. Once the black console opens up type ping www.google.com and this should give you and IP address for google. This address is googles local IP and they bind to that and obviously you can not bind to an IP address owned by google.

With that in mind, you own your own set of IP addresses. First you have the local IP of the server, but then you have the local IP of your house. In the below picture 192.168.1.50 is the local IP of the server which you can bind to. You still own 83.55.102.40 but the problem is that it's owned by the Router and not your server. So even if you visit http://whatsmyip.com and that tells you that your IP is 83.55.102.40 that is not the case because it can only see where you're coming from.. and you're accessing your internet from a router.

enter image description here

In order for your friends to access your server (which is bound to 192.168.1.50) you need to forward port 6677 to 192.168.1.50 and this is done in your router. Assuming you are behind one.

If you're in school there's other dilemmas and routers in the way most likely.

Gulzar
  • 23,452
  • 27
  • 113
  • 201
Torxed
  • 22,866
  • 14
  • 82
  • 131
  • 2
    Thank you for explaining this. How does this change if you are using a cloud server. Lets say from AWS? – Gabriel Fair Nov 10 '17 at 22:23
  • 4
    @GabrielFair Not sure, since I don't use cloud services. I always use self-hosted servers where I can control the hardware :) The easiest workaround would be to just do `server.bind(("", 6677))` in this case, because that would bind to all available interfaces on port 6677 - rather than limiting yourself to a known IP. I know that AWS usually change IP's externally, but internally they should stay the same. You can also use one of these: https://stackoverflow.com/questions/270745/how-do-i-determine-all-of-my-ip-addresses-when-i-have-multiple-nics – Torxed Nov 11 '17 at 07:50
  • 1
    How to check if no other software is listening to selected port? – Naveen Kumar Dec 07 '18 at 06:54
  • 1
    @NaveenKumar depends on your OS. `ss -lp | grep 6677` for instance. – Torxed Dec 07 '18 at 07:06
  • @Torxed I am using Ubuntu `$ ss -lp | grep 6010 tcp LISTEN 0 128 127.0.0.1:6010 0.0.0.0:* tcp LISTEN 0 128 [::1]:6010` [::]:* – Naveen Kumar Dec 07 '18 at 07:29
  • I see that this is an excellent explanation, but could you mention if the code snippet was for the server or the client ? (Sorry if it sounds like a noob asking) – Pe Dro Jan 15 '21 at 17:59
  • @PeDro It's for the server software, which in turn usually runs on a server some where :) Clients don't use `bind()`, they use `connect()` instead. – Torxed Jan 15 '21 at 22:48
52

This error will also appear if you try to connect to an exposed port from within a Docker container, when nothing is actively serving the port.

On a host where nothing is listening/bound to that port you'd get a No connection could be made because the target machine actively refused it error instead when making a request to a local URL that is not served, eg: localhost:5000. However, if you start a container that binds to the port, but there is no server running inside of it actually serving the port, any requests to that port on localhost will result in:

  • [Errno 99] Cannot assign requested address (if called from within the container), or
  • [Errno 0] Error (if called from outside of the container).

You can reproduce this error and the behaviour described above as follows:

Start a dummy container (note: this will pull the python image if not found locally):

docker run --name serv1 -p 5000:5000 -dit python

Then for [Errno 0] Error enter a Python console on host, while for [Errno 99] Cannot assign requested address access a Python console on the container by calling:

docker exec -it -u 0 serv1 python

And then in either case call:

import urllib.request
urllib.request.urlopen('https://localhost:5000')

I concluded with treating either of these errors as equivalent to No connection could be made because the target machine actively refused it rather than trying to fix their cause - although please advise if that's a bad idea.


I've spent over a day figuring this one out, given that all resources and answers I could find on the [Errno 99] Cannot assign requested address point in the direction of binding to an occupied port, connecting to an invalid IP, sysctl conflicts, docker network issues, TIME_WAIT being incorrect, and many more things. Therefore I wanted to leave this answer here, despite not being a direct answer to the question at hand, given that it can be a common cause for the error described in this question.

Voy
  • 5,286
  • 1
  • 49
  • 59
  • 8
    Good digging! Thank you! Still happens in 2020 – Zaar Hai Dec 14 '20 at 06:58
  • Great, that was something resourceful and saved a lot of google browsing...Thanks – ronit May 04 '21 at 13:28
  • Great observation, thanks for sharing. It was really scary when I've seen os error 99 for a first time under the same circumstances. Although, I'm still interested why exactly this happens? It seems to be related to how Docker runtime reserves/routes exposed ports from within the container, but I'd be really glad to know the real implementation details. – ololobus Nov 22 '21 at 15:26
14

Try like this:

server.bind(("0.0.0.0", 6677)) 
Gulzar
  • 23,452
  • 27
  • 113
  • 201
WindyYang
  • 151
  • 1
  • 3
12

When you bind localhost or 127.0.0.1, it means you can only connect to your service from local.

You cannot bind 10.0.0.1 because it not belong to you, you can only bind ip owned by your computer

You can bind 0.0.0.0 because it means all ip on your computer, so any ip can connect to your service if they can connect to any of your ip

Gulzar
  • 23,452
  • 27
  • 113
  • 201
eastonsuo
  • 935
  • 9
  • 11
0

This is not directly answering the question, but is a debugging direction in case above solutions failed.
When you are not on a native environment, let's say you are on a VM or WSL, the inside network might not be transparent to external computer due to NATing. So make sure you can ping the IP from wherever you are trying to bind. If not, then consider switching to the correct environment or consider network bridging. If you are looking for a WSL2 specific solution, you may try this link: Bridging WSL2 network adapter with Windows In Virtual Box you may change Network Adapter -> Attached To: Bridged Adapter. The other consideration is if you are trying to bind to a port <1023 you need admin privilege.

Gulzar
  • 23,452
  • 27
  • 113
  • 201
Kartik Javali
  • 327
  • 1
  • 4
  • 11
0

This was what I need on a remote VM:

jupyter notebook --ip=0.0.0.0 --port=8888

Copied from here

gndps
  • 461
  • 3
  • 13
0

In my case, I was running a container in Ubuntu server with Postgres running in another container in localhost (exposed with -p 5432:5432) to which I was trying to connect. I tried all types of addresses: localhost 127.0.0.1 0.0.0.0 for the connection string postgresql://user:password@localhost:5432/db but they either returned a timeout error or in case of localhost: Io(Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" })

Pretty frustrating since it worked locally and I really didn't want to mess with the Docker network configurations. Luckily, I recalled fixing similar bug (if not the same one) long time ago where I just had to replace localhost with the Docker machine IP when in Linux.

172.17.0.1 worked without problems. Hopefully this helps somebody else.

TeemuK
  • 2,095
  • 1
  • 18
  • 17