Python中的socket.error:[errno 99] cannot assign requested address和namespace是什么意思?

84

我的服务器软件在绑定IP地址时,如果使用除 127.0.0.1 以外的其他IP地址,则会显示errno99: cannot assign requested address错误。

但是如果使用IP地址为 127.0.0.1,则可以正常运行。 这与名称空间有关吗?

我通过调用 execfile() 在另一个Python程序中执行我的服务器和客户端代码。 实际上,我正在编辑mininet源代码。我编辑了net.py,在其中使用了execfile('server.py')execfile('client1.py')和 execfile('client2.py')。因此,一旦调用“sudo mn --topo single,3”并创建了3个主机,我的服务器和客户端代码将得到执行。我在下面提供了我的服务器和客户端代码。

#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()

展示一些代码,否则我们无法帮助您。(最好展示如何设置套接字以及如何通过调用execfile()来执行“服务器”(顺便问一下,使用execfile()的原因是什么?)) - Torxed
1
当您尝试使用127.0.0.1以外的其他内容时,您使用的是哪个地址?我通过绑定到一些无效的IP来重现了您的错误。请记住,服务器只能绑定在自身上,因此您提供的IP或名称必须是服务器中的一个... - mguijarr
1
当你调用bind()函数时,你会将socket与本地IP地址和端口号关联起来。因此,只要地址是本地的,包括127.0.0.1(本地主机地址),bind()函数就可以工作。但是,如果尝试绑定到非本地地址,则会导致上述错误。 - Manoj Pandey
@Torxed,我已经编辑了问题,请仔细查看。 - user2833462
1
@user2833462 10.x.x.x172.16.x.x192.168.x.x127.0.0.x 是本地网络。但遗憾的是,83.127.224.44 是一个本地地址(而且这是你想要绑定的本地地址),因为它是分配给你的计算机的地址。 (也就是说,你不能bind()到“www.google.com”,因为你不拥有它,但如果你拥有“www.made-up-example.com”,你就可以绑定到那个地址,一旦你理解了这个基本概念,你需要绑定到made-up-example.com的*IP*而不是地址本身)。 - Torxed
显示剩余2条评论
7个回答

67

简化为基础测试,这是您想要测试的内容:

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)

假设以下几点成立:

  1. 您本地服务器的IP地址为10.0.0.1(此视频将向您展示如何操作
  2. 没有其他软件在端口6677上监听

请注意IP地址的基本概念:

尝试以下步骤:打开开始菜单,在“搜索”字段中输入cmd并按Enter键。 一旦黑色控制台打开,请键入ping www.google.com,这应该会为google提供一个IP地址。 这个地址是google的本地IP地址,它们绑定到那个地址,很明显你不能绑定到由google拥有的IP地址。

考虑到这一点,您可以拥有自己的一组IP地址。 首先,您有服务器的本地IP,然后您有家里的本地IP。 在下面的图片中,192.168.1.50是您可以绑定的服务器的本地IP。 您仍然��有83.55.102.40,但问题在于它是由路由器拥有而不是您的服务器。因此,即使您访问http://whatsmyip.com并且它告诉您您的IP地址为83.55.102.40,这并不是正确的,因为它只能看到您来自哪里..而您是通过路由器访问互联网的。

enter image description here

为使您的朋友可以访问您绑定到192.168.1.50的服务器,您需要将端口6677转发到192.168.1.50,这可以在您的路由器中完成。 假设您在路由器后面。

如果您在学校,则可能存在其他问题和路由器。


2
谢谢您解释这个。 如果您使用云服务器,比如AWS,会有什么变化呢? - Gabriel Fair
4
@GabrielFair 我不确定,因为我不使用云服务。我总是使用可以控制硬件的自托管服务器:) 在这种情况下,最简单的解决方法是只需执行server.bind(("", 6677)),因为这将绑定到端口6677上的所有可用接口 - 而不是限制自己到已知IP。我知道AWS通常会在外部更改IP,但在内部它们应该保持不变。您还可以使用其中之一:https://dev59.com/e3VC5IYBdhLWcg3whBaj - Torxed
1
如何检查是否有其他软件正在监听所选端口? - Naveen Kumar
1
@NaveenKumar 这取决于您的操作系统。例如,可以使用 ss -lp | grep 6677 - Torxed
@PeDro 这是针对服务器软件的,通常在某个服务器上运行 :) 客户端不使用 bind(),而是使用 connect() - Torxed
显示剩余2条评论

54
如果您尝试从Docker容器内部连接到一个暴露的端口,但没有任何东西在服务该端口,则会出现此错误。如果在主机上没有任何内容侦听/绑定到该端口,则在尝试请求未提供服务的本地URL(例如:localhost:5000)时,您将收到“无法建立连接,因为目标计算机积极拒绝”错误。但是,如果您启动了一个绑定到该端口的容器,并且没有运行实际服务该端口的服务器,则在本地主机上对该端口进行任何请求都将导致以下结果:[Errno 99] Cannot assign requested address(如果从容器内部调用)或[Errno 0] Error(如果从容器外部调用)。您可以按照以下方式复制此错误和上述所描述的行为:启动虚拟容器(请注意:如果本地不存在python镜像,则会拉取python镜像)。
docker run --name serv1 -p 5000:5000 -dit python

对于[Errno 0]错误,在主机上进入Python控制台,而对于[Errno 99]无法分配请求的地址,通过调用以下内容访问容器中的Python控制台:

docker exec -it -u 0 serv1 python

然后在任何一种情况下都要调用:

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

我得出结论,将这些错误视为等同于无法建立连接,因为目标计算机主动拒绝了它,而不是试图修复其原因 - 但如果这是一个坏主意,请提醒我。


我花了一天以上的时间来找出这个问题,因为我在[Errno 99] Cannot assign requested address上找到的所有资源和答案都指向绑定到被占用的端口连接到无效 IPsysctl冲突docker 网络问题TIME_WAIT 不正确等方向。因此,尽管这不是对手头问题的直接答案,但我仍想在这里留下这个答案,因为它可能是描述此问题的错误的常见原因。


8
好的,谢谢您的委托!2020年仍在发生。 - Zaar Hai
太好了,这是非常有用的资源,省去了很多谷歌搜索...谢谢。 - ronit
非常棒的观察,谢谢你分享。在同样的情况下第一次看到操作系统错误99时,我感到非常害怕。尽管如此,我仍然很想知道为什么会发生这种情况?这似乎与Docker运行时如何从容器内部保留/路由暴露端口有关,但我真的很想知道实际的实现细节。 - ololobus
1
这应该是被接受的答案。错误信息非常不直观。 - undefined

15

试试这样:

server.bind(("0.0.0.0", 6677)) 

1
这真的有效!你能解释一下为什么我可以使用这个IP地址吗?谢谢! - YanjieZe

12
当你绑定“localhost”或“127.0.0.1”的时候,这意味着你只能从本地连接到你的服务。
你不能绑定“10.0.0.1”,因为它不属于你,你只能绑定你计算机拥有的IP。
你可以绑定“0.0.0.0”,因为它代表你计算机上的所有IP,所以如果他们可以连接到你的任何IP,则任何IP都可以连接到你的服务。

0

这并不是直接回答问题,而是在上述解决方案失败的情况下进行调试。
当您不在本地环境中时,比如在虚拟机或WSL上,由于NAT,内部网络可能对外部计算机不透明。因此,请确保您可以从任何您尝试绑定的位置ping通该IP地址。如果不能,请考虑切换到正确的环境或考虑网络桥接。 如果您正在寻找WSL2特定的解决方案,可以尝试使用此链接: Bridging WSL2 network adapter with Windows 在Virtual Box中,您可以更改网络适配器 -> 附加到:桥接适配器。 另一个需要考虑的问题是,如果您尝试绑定到<1023端口,则需要管理员权限。


0

这是我需要在远程虚拟机上的内容:

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

这里复制


0
在我的情况下,我在Ubuntu服务器上运行一个容器,其中Postgres在另一个容器中以本地主机形式运行(使用 -p 5432:5432 暴露),我试图连接到它。我尝试了所有类型的地址:localhost 127.0.0.1 0.0.0.0,对于连接字符串postgresql://user:password@localhost:5432/db,但它们要么返回超时错误,要么在 localhost 的情况下返回:Io(Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" })
这真让人沮丧,因为它在本地工作正常,而且我真的不想去处理Docker网络配置。幸运的是,我记得很久以前修复过类似的错误(如果不是同一个),那时我只需要在Linux中用Docker机器的IP替换localhost。 172.17.0.1可以正常工作。希望这对其他人有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接