No localhost, como escolho um número de porta gratuito?

160

Estou tentando jogar com a comunicação entre processos e, como não consegui descobrir como usar pipes nomeados no Windows, pensei em usar soquetes de rede. Tudo acontece localmente. O servidor é capaz de iniciar escravos em um processo separado e escuta em alguma porta. Os escravos fazem seu trabalho e enviam o resultado ao mestre. Como faço para descobrir qual porta está disponível? Presumo que não posso ouvir na porta 80 ou 21?

Estou usando Python, se isso reduzir as opções.

Obrigado!

Anton L.
fonte
1
Aliás, se você escolher um número de porta aleatória ou aleatória (de preferência maior que 1024), provavelmente estará disponível. Você pode até usar a porta 80 ou 21 ou qualquer outra coisa, desde que nenhum outro programa esteja escutando nela. A qualquer momento, em um sistema normal, apenas uma pequena fração de portas está em uso.
589 David Z
19
Escolher uma porta aleatória não é uma boa ideia - deixe o sistema operacional escolher uma para você.
Corehpf 02/09/09
No POSIX: stackoverflow.com/questions/913501/…
Ciro Santilli escreveu:

Respostas:

224

Não ligue a uma porta específica ou ligue à porta 0, por exemplo sock.bind(('', 0)). O sistema operacional escolherá uma porta disponível para você. Você pode obter a porta que foi escolhida usando sock.getsockname()[1]e passá-la aos escravos para que eles possam se conectar novamente.

mark4o
fonte
4
Veja stackoverflow.com/a/2838309/3538289 para obter um exemplo desock.bind(('',0))
cevaris
10
Como você passa o número para os escravos? Parece um problema de galinha e ovo para mim.
23716 Sebastian
2
Se os escravos forem criados após a ligação, basta passar como parâmetro ao criá-los. Como alternativa, você pode gravá-lo em alguma memória compartilhada ou em um arquivo que ambos possam acessar, ou um servidor central acessado por meio de um número de porta conhecido pode acompanhar.
mark4o
49

Por uma questão de trecho do que os caras explicaram acima:

import socket
from contextlib import closing

def find_free_port():
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.bind(('', 0))
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        return s.getsockname()[1]
saaj
fonte
3
se em localhost: talvez s.bind(('localhost', 0))é melhor
codeskyblue
3
Também é bom para adicionar a seguinte assim que você rapidamente pode reutilizar essa porta antes de sua instrução de retorno:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird
1
@jonEbird socket.SO_REUSEADDRRealmente ajuda nesse caso? Pelo que li, é relevante apenas que o soquete que está tentando vincular tenha SO_REUSEADDRe é irrelevante se esse sinalizador está definido no soquete remanescente.
Karl Bartel
41

Ligue o soquete à porta 0. Uma porta livre aleatória de 1024 a 65535 será selecionada. Você pode recuperar a porta selecionada getsockname()logo após bind().

Havenard
fonte
2

Você pode ouvir em qualquer porta que desejar; geralmente, os aplicativos do usuário devem ouvir as portas 1024 e superiores (até 65535). O principal, se você tiver um número variável de ouvintes, é alocar um intervalo para seu aplicativo - digamos 20000-21000 e CATCH EXCEPTIONS . É assim que você saberá se uma porta não pode ser usada (usada por outro processo, em outras palavras) no seu computador.

No entanto, no seu caso, você não deve ter problemas ao usar uma única porta codificada para o seu ouvinte, desde que imprima uma mensagem de erro se a ligação falhar.

Observe também que a maioria dos seus soquetes (para os escravos) não precisa ser explicitamente vinculada a números de porta específicos - apenas os soquetes que aguardam conexões de entrada (como seu mestre aqui) precisarão ser ouvintes e vinculados a uma porta. Se uma porta não for especificada para um soquete antes de ser usada, o sistema operacional atribuirá uma porta utilizável ao soquete. Quando o mestre deseja responder a um escravo que envia dados, o endereço do remetente fica acessível quando o ouvinte recebe dados.

Eu presumo que você estará usando o UDP para isso?

Walt W
fonte
0

Se você precisar encontrar apenas uma porta livre para uso posterior , veja um trecho semelhante a uma resposta anterior , mas mais curto, usando o socketserver :

import socketserver

with socketserver.TCPServer(("localhost", 0), None) as s:
    free_port = s.server_address[1]

Observe que a porta não é garantida para permanecer livre, portanto, você pode precisar colocar esse trecho e o código usando-o em um loop.

Mihai Capotă
fonte