选择远程主机上的随机端口

时间:2014-02-17 11:25:55

标签: python sockets

我想在远程linux机器上选择一个随机高端口并将其用于我的应用程序。在我的localhost上,我可以绑定到端口0并获得一个随机的高端口,但如果我给一个远程主机,这不起作用。

代码如下:

host = "remote_host"

def get_open_port():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host,0))
    s.listen(1)
    port = s.getsockname()[1]
    s.close()
    return port

错误:

Traceback (most recent call last):
  File "server.py", line 25, in <module>
    port = get_open_port()
  File "server.py", line 11, in get_open_port
    s.bind((host,0))
  File "<string>", line 1, in bind

1 个答案:

答案 0 :(得分:2)

嗯,我想你对客户端 - 服务器通信有点困惑。在找到问题的解决方案之前,首先重新访问客户端 - 服务器通信过程。通常,客户端向服务器发出/发起连接请求(只是连接)。客户端在侦听传入连接的远程端口上向服务器发出请求。此远程端口应在服务器端打开,并应等待传入连接。例如:如果要连接远程端口号为15200的远程服务器,则必须在服务器端打开端口号15200,并且应该监听任何传入的连接/请求。此外,客户端会事先知道它应该向哪个远程端口发出连接请求!

在了解问题的可能解决方案之前,让我们了解一些更多的事实。首先让我们了解服务器端。

服务器端:您正在尝试使用任何随机端口来接受来自客户端的传入连接。当您将服务器代码中的端口号0绑定为s.bind((host,0))时,它肯定会起作用。当您绑定端口号0时,您的服务器(实际上是运行服务器脚本的操作系统)将使用任何随机高端口号来接受通常更大的远程连接。您可以通过以下代码片段对此进行测试。运行以下代码段,您可能会注意到服务器正在打开随机高端口号。

import socket
host = "127.0.0.1"

def get_open_port():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind((host,0))
    s.listen(1)
    port = s.getsockname()[1]
    s.close()
    return port

for i in range(0,5):
        print "Opening port no. %s"%get_open_port()

在执行上述代码时,您将看到服务器代码正在选择随机端口号,以便每次都接受传入连接。但是在使用s.close()的病房之后它也正在关闭它。在我的情况下,输出如下(您可能会得到一组不同的端口号):

Opening port no. 60876
Opening port no. 60877
Opening port no. 60878
Opening port no. 60879
Opening port no. 60880

所以,我想现在你理解了服务器部分。让我们现在讨论客户端。

客户端:如前所述,客户端需要知道它需要连接的远程服务器端口。典型的客户端代码如下所示:

import socket
host = "127.0.0.1"
port = 60880
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

在上面的代码段s.connect((host, port))中,您需要提及host 远程主机名或IP port 远程端口您想要连接到。 所以这意味着客户应该提前知道端口号!因此,您必须在客户端代码中提及port。正如我在我的代码段中所做的那样port = 60880

现在提出您的问题:正如您已经从上面的文字中注意到的那样,您必须在客户端代码中提及远程服务器的端口号以请求连接。因此,您不能指望您的客户端自己找出实际正在侦听传入请求的服务器的远程端口。客户端代码不能单独执行此操作。

解决方案:

那么,如果客户端代码无法自己弄清楚远程端口号,我们会让它弄明白! ;)我们知道如果你在服务器端绑定端口号0,那么将选择一个大于1023的随机端口号。因此,这意味着随机端口号将始终大于1023. {{3}最后,我们得出结论,服务器使用的随机端口将是此范围1024 - 65335中的任何端口号。 现在,您只需要在客户端代码中使用一系列应该连接的端口号。因为我们不知道服务器端正在侦听哪个远程端口接受传入的请求/连接!

示例代码用于浏览:我使用 Also, the maximum value of port number is 65535. 测试了这些代码段。这是服务器代码。首先运行服务器代码,然后运行客户端代码。在执行服务器代码时,它将在控制台/输出中显示为接受传入请求/连接而打开的随机端口号是什么。连接客户端后,服务器将显示已连接客户端连同客户端IP的消息。

#This is the server script
import socket
host = "127.0.0.1"

def get_open_port():
    mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    mySocket.bind((host,0))
    mySocket.listen(1)
    port = mySocket.getsockname()[1]
    print "Port opened for incoming connections %d"%port
    (clientSocket, clientAddress) = mySocket.accept()
    print "Got a client: ", clientAddress
    clientSocket.close()
    mySocket.close()

get_open_port()

这是一个客户端代码示例,它会做这个疯狂的事情。它将尝试连接1024 - 65335的所有端口,并在找到任何正在侦听传入连接的远程端口时。它将显示一条消息“已连接到远程端口”,然后关闭套接字并继续查找更多打开的端口,直到它到达最后一个端口号65355。

#This is the client script
import socket
host = "127.0.0.1"

def startConn():
    for port in range(1024,65336):
        try:
            myClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            print "Trying remote port: ",port
            myClientSocket.connect((host,port))
            print "Connected to remote port: ",port
            myClientSocket.close()
        except socket.error as msg:
            myClientSocket.close()
            continue

startConn()

这只是一个示例代码,我在成功建立后故意关闭套接字。你可以做任何你喜欢的事情。我希望你现在对服务器 - 客户端通信很清楚。