Лучший способ узнать, какой порт выбран на стороне клиента - PullRequest
2 голосов
/ 26 мая 2020

Моя программа случайным образом выбирает порт на стороне сервера, используя адрес ('0.0.0.0', 0), и уникальный code отправляется на сторону клиента, где сокет пытается подключиться к каждому порту в пределах диапазона и проверяет наличие того же code для подтверждения правильности порта сервера.

Проблема заключается в переборе всех портов (range(1024, 65336)), и попытки подключиться к каждому из них очень медленны, даже если используется ThreadPool.


Это просто пример, чтобы показать, что я пытаюсь сделать. Мой основной программный хост через inte rnet не на localhost.

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)

Есть ли лучший способ достичь этой цели или повысить производительность моего существующего кода?

Ответы [ 2 ]

4 голосов
/ 26 мая 2020

Не прямой ответ, но слишком длинный для комментария.

Это не тот способ, которым предполагается использовать случайные порты. Они используются для передачи данных в протоколе FTP следующим образом (пассивный режим):

  • клиент открывает управляющее соединение на хорошо известном порту (21)
  • он запрашивает сервер для произвольного порта данных через управляющее соединение
  • он открывает соединение для передачи данных зная свой порт

Открывает случайное соединение портов следует избегать, потому что, если сервер не отвечает немедленно, клиент должен дождаться тайм-аута, чтобы решить, был ли сервер просто занят или нет.

Итак, мой совет, если вы хотите использовать случайные порты - сохранить один хорошо известный порт, на котором клиент получит настоящий случайный порт.

0 голосов
/ 26 мая 2020

nmap предоставляет способы сделать это. Вот пример кода из этой страницы :

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.

Однако я скажу, что случайное назначение порта сервера нецелесообразно, и вам, вероятно, лучше просто назначить фиксированный порт.

...