【问题标题】:Best way to find which port is selected from client-side查找从客户端选择的端口的最佳方法
【发布时间】:2020-09-13 07:30:03
【问题描述】:

我的程序使用地址('0.0.0.0', 0) 随机选择服务器端端口,并将唯一的code 发送到客户端,其中套接字试图连接到范围内的每个端口并检查相同的@987654324 @ 确认正确的服务器端口。

问题在于遍历所有端口(@98​​7654325@),即使使用ThreadPool,尝试连接每个端口也非常慢。


这只是展示我正在尝试做的一个例子。我的主程序通过互联网而不是本地主机托管。

server.py

import socket 

CODE = 'Code123' # just an example

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
addr = ('0.0.0.0', 0)
server.bind(addr)

# Can see which port is assigned
print(server)

def start():
    server.listen(5) # connect to 5 connection.
    while True:
        conn, addr = server.accept()
        conn.send(CODE.encode('utf-8'))
        print("Code Sent")

start()

cilent.py

import socket
from multiprocessing.pool import ThreadPool

code = 'Code123' # just an example
server = socket.gethostbyname(socket.gethostname())
port_left = 65336
found = False

def connect(port):
    global port_left, code, server, found
    if found: return
    port_left -= 1
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect((server, port))
        if client.recv(len(code)).decode('utf-8') == code:
            found = True
            return client
        else: client.close()
    except Exception as e:
        print(e, port_left)
    return None

pool = ThreadPool(10)
values = [('c', i) for i in set(pool.map(connect, range(1024, 65336))) if i]
client = dict(values).get('c')
pool.close()
pool.join()
print(client)

有没有更好的方法来实现这个目标或提高我现有代码的性能?

【问题讨论】:

  • 如果您这样考虑:如果您的服务器或客户端之一必须启动与另一个的对话,那么哪个更符合逻辑以具有服务所在的“固定”端口?在那里设置一个静态端口,然后回复该设备上消息来自的端口。
  • 随机套接字的目的是什么,为什么不只是有一个固定的端口?这也避免了与其他服务器软件端口冲突的问题。
  • 添加另一个如何思考的示例:HTTP 通常在 TCP 端口 80 上响应。因此,服务器有其 Web 服务服务于该端口上的 HTTP 请求。但是,客户端没有特定的 TCP 端口来发送请求,因此服务器会响应它接收消息的 TCP 端口。因此,他们可以互相交谈。
  • @HampusLarsson:如果该固定端口稍后被其他人占用并且我的脚本尝试连接同一个端口怎么办?
  • “如果那个固定端口后来忙了怎么办……”这应该永远不会发生。例如,如果服务器已配置并正在运行,则应该没有任何东西可以使用服务器上的该端口。你的思维方式有问题。请检查a list of well-known ports 并选择与您的应用程序完全相同的端口,或添加服务应使用的“备份”端口。

标签: python sockets networking multiprocessing threadpool


【解决方案1】:

不是一个直接的答案,但评论太长了。

这不是随机端口的预期使用方式。它们用于FTP协议中的数据连接方式(被动模式):

  • 客户端在已知端口 (21) 上打开控制连接
  • 它通过控制连接向服务器请求随机数据端口
  • 它打开数据连接知道它的端口

应避免在随机端口上打开连接,因为如果服务器没有立即响应,客户端必须等待超时来确定服务器是否只是忙。

因此,如果您想使用随机端口,我的建议是保留一个众所周知的端口,客户端将在该端口上获取真正的随机端口。

【讨论】:

  • 感谢您通过答案进行解释,这个简单易行。您还说不是期望使用随机端口的方式,那么可以使用知名端口与多个客户端建立连接并发送大数据吗?
  • @Saad:有两个很好的例子可以在为许多客户端服务的同时发送大数据:FTP 和 HTTP 协议。 HTTP 使用一个众所周知的端口 (80) 来传输客户端命令和数据。 FTP 为命令使用一个众所周知的端口,为数据使用随机端口(每个数据连接一个端口)。好的部分是它允许客户端在 2 个远程主机之间启动传输。但是这个特性很快就被弃用了,因为它被用来发起 DoD 攻击。随机端口现在不受欢迎,因为它们会让防火墙管理员头疼......
【解决方案2】:

nmap 提供了执行此操作的方法。这是来自this page的示例代码:

import nmap 

# take the range of ports to  
# be scanned 
begin = 75
end = 80

# assign the target ip to be scanned to 
# a variable 
target = '127.0.0.1'

# instantiate a PortScanner object 
scanner = nmap.PortScanner() 

for i in range(begin,end+1): 

    # scan the target port 
    res = scanner.scan(target,str(i)) 

    # the result is a dictionary containing  
    # several information we only need to 
    # check if the port is opened or closed 
    # so we will access only that information  
    # in the dictionary 
    res = res['scan'][target]['tcp'][i]['state'] 

    print(f'port {i} is {res}.') 

输出:

port 75 is closed.
port 76 is closed.
port 77 is closed.
port 78 is closed.
port 79 is closed.
port 80 is open.

但是,我会说随机分配服务器端口是不切实际的,您最好只分配一个固定端口。

【讨论】:

  • 感谢您的回答,但我想在没有任何外部软件包的情况下执行此操作。
  • 如果您不使用任何外部软件包,那么您创建套接字并查看它是否连接的方法可能已经是最好的方法了。它会很慢,但它有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 2019-08-30
  • 2011-03-08
  • 1970-01-01
  • 2016-07-03
  • 2019-04-03
  • 1970-01-01
相关资源
最近更新 更多