Na programação de soquete, você cria um soquete de escuta e, para cada cliente que se conecta, obtém um soquete de fluxo normal que pode ser usado para lidar com a solicitação do cliente. O sistema operacional gerencia a fila de conexões de entrada nos bastidores.
Dois processos não podem se vincular à mesma porta ao mesmo tempo - por padrão, de qualquer maneira.
Estou me perguntando se há uma maneira (em qualquer sistema operacional conhecido, especialmente Windows) para iniciar várias instâncias de um processo, de modo que todas elas se liguem ao soquete e, assim, compartilhem efetivamente a fila. Cada instância de processo pode então ter um único encadeamento; ele apenas bloquearia ao aceitar uma nova conexão. Quando um cliente se conectava, uma das instâncias de processo ociosas aceitaria esse cliente.
Isso permitiria que cada processo tivesse uma implementação de thread única muito simples, sem compartilhar nada, a menos que por meio de memória compartilhada explícita, e o usuário seria capaz de ajustar a largura de banda de processamento iniciando mais instâncias.
Esse recurso existe?
Edit: Para aqueles que perguntam "Por que não usar tópicos?" Obviamente, os tópicos são uma opção. Mas com vários threads em um único processo, todos os objetos são compartilháveis e muito cuidado deve ser tomado para garantir que os objetos não sejam compartilhados ou sejam visíveis apenas para um thread de cada vez, ou sejam absolutamente imutáveis, e as linguagens mais populares e tempos de execução carecem de suporte integrado para gerenciar essa complexidade.
Ao iniciar um punhado de processos de trabalho idênticos, você obteria um sistema simultâneo no qual o padrão é nenhum compartilhamento, tornando muito mais fácil construir uma implementação correta e escalável.
fonte
Respostas:
Você pode compartilhar um soquete entre dois (ou mais) processos no Linux e até no Windows.
No Linux (ou sistema operacional do tipo POSIX), o uso
fork()
fará com que o filho bifurcado tenha cópias de todos os descritores de arquivo do pai. Qualquer coisa que ele não fechar continuará a ser compartilhada e (por exemplo, com um soquete de escuta TCP) pode ser usado paraaccept()
novos soquetes para clientes. É assim que muitos servidores, incluindo o Apache na maioria dos casos, funcionam.No Windows, a mesma coisa é basicamente verdadeira, exceto que não há
fork()
chamada de sistema, então o processo pai precisará usarCreateProcess
ou algo para criar um processo filho (que pode, é claro, usar o mesmo executável) e precisa passar para ele um identificador herdável.Tornar um soquete de escuta um identificador herdável não é uma atividade completamente trivial, mas também não é muito complicada.
DuplicateHandle()
precisa ser usado para criar um identificador duplicado (ainda no processo pai), que terá o sinalizador herdável definido nele. Em seguida, você pode fornecer esse identificador naSTARTUPINFO
estrutura para o processo filho em CreateProcess como umSTDIN
,OUT
ouERR
identificador (assumindo que você não deseja usá-lo para mais nada).EDITAR:
Lendo a biblioteca MDSN, parece que
WSADuplicateSocket
é um mecanismo mais robusto ou correto de fazer isso; ainda não é trivial porque os processos pai / filho precisam descobrir qual identificador precisa ser duplicado por algum mecanismo IPC (embora isso possa ser tão simples quanto um arquivo no sistema de arquivos)ESCLARECIMENTO:
Em resposta à pergunta original do OP, não, os processos múltiplos não podem
bind()
; apenas o processo pai original chamariabind()
,listen()
etc, os processos filho só iria processar os pedidos poraccept()
,send()
,recv()
etc.fonte
Muitos outros forneceram as razões técnicas pelas quais isso funciona. Aqui estão alguns códigos python que você pode executar para demonstrar isso por si mesmo:
Observe que, de fato, existem dois IDs de processo escutando:
Aqui estão os resultados da execução do telnet e do programa:
fonte
Eu gostaria de acrescentar que os sockets podem ser compartilhados no Unix / Linux via sockets AF__UNIX (sockets inter-processo). O que parece acontecer é que um novo descritor de soquete é criado, algo como um alias do original. Este novo descritor de socket é enviado através do socket AFUNIX para o outro processo. Isso é especialmente útil nos casos em que um processo não pode fazer fork () para compartilhar seus descritores de arquivo. Por exemplo, ao usar bibliotecas que evitam isso devido a problemas de threading. Você deve criar um soquete de domínio Unix e usar libancillary para enviar o descritor.
Vejo:
Para criar soquetes AF_UNIX:
Por exemplo de código:
fonte
Parece que essa pergunta já foi respondida totalmente por MarkR e zackthehack, mas eu gostaria de acrescentar que o Nginx é um exemplo do modelo de herança de soquete de escuta.
Aqui está uma boa descrição:
fonte
Não tenho certeza se isso é relevante para a questão original, mas no kernel do Linux 3.9 há um patch adicionando um recurso TCP / UDP: suporte TCP e UDP para a opção de soquete SO_REUSEPORT; A nova opção de soquete permite que vários soquetes no mesmo host se vinculem à mesma porta e tem como objetivo melhorar o desempenho de aplicativos de servidor de rede multithread rodando em sistemas multicore. mais informações podem ser encontradas no link LWN LWN SO_REUSEPORT no Linux Kernel 3.9 conforme mencionado no link de referência:
a opção SO_REUSEPORT não é padrão, mas está disponível em uma forma semelhante em vários outros sistemas UNIX (notavelmente, os BSDs, onde a ideia se originou). Parece oferecer uma alternativa útil para obter o máximo desempenho dos aplicativos de rede executados em sistemas com vários núcleos, sem ter que usar o padrão fork.
fonte
SO_REUSEPORT
cria um pool de threads, onde cada socket está em um thread diferente, mas apenas um socket no grupo executa oaccept
. Você pode confirmar se todos os sockets no grupo obtêm uma cópia dos dados?A partir do Linux 3.9, você pode definir o SO_REUSEPORT em um soquete e, em seguida, ter vários processos não relacionados compartilhando esse soquete. Isso é mais simples do que o esquema prefork, sem mais problemas de sinal, vazamento de fd para processos filho, etc.
Linux 3.9 introduziu uma nova maneira de escrever servidores de soquete
A opção de soquete SO_REUSEPORT
fonte
Tenha uma única tarefa cujo único trabalho seja ouvir as conexões de entrada. Quando uma conexão é recebida, ele aceita a conexão - isso cria um descritor de soquete separado. O soquete aceito é passado para uma de suas tarefas de trabalho disponíveis e a tarefa principal volta a escutar.
fonte
No Windows (e Linux), é possível que um processo abra um soquete e, em seguida, passe esse soquete para outro processo, de modo que esse segundo processo também possa usar esse soquete (e passá-lo adiante, se desejar) .
A chamada de função crucial é WSADuplicateSocket ().
Isso preenche uma estrutura com informações sobre um soquete existente. Essa estrutura então, por meio de um mecanismo IPC de sua escolha, é passada para outro processo existente (observe que digo existente - quando você chama WSADuplicateSocket (), você deve indicar o processo de destino que receberá a informação emitida).
O processo de recebimento pode então chamar WSASocket (), passando essa estrutura de informações e receber um identificador para o soquete subjacente.
Ambos os processos agora mantêm um identificador para o mesmo soquete subjacente.
fonte
Parece que o que você deseja é um processo de escuta de novos clientes e, em seguida, desligue a conexão quando você conseguir uma conexão. Fazer isso entre threads é fácil e em .Net você ainda tem os métodos BeginAccept etc. para cuidar de grande parte do encanamento para você. Transferir as conexões através dos limites do processo seria complicado e não teria nenhuma vantagem de desempenho.
Alternativamente, você pode ter vários processos vinculados e escutando no mesmo soquete.
Se você iniciar dois processos, cada um executando o código acima, ele funcionará e o primeiro processo parece obter todas as conexões. Se o primeiro processo for encerrado, o segundo obterá as conexões. Com o compartilhamento de soquete como esse, não sei exatamente como o Windows decide qual processo obtém novas conexões, embora o teste rápido aponte para o processo mais antigo obtendo-as primeiro. Se ele compartilha se o primeiro processo está ocupado ou algo assim, eu não sei.
fonte
Outra abordagem (que evita muitos detalhes complexos) no Windows, se você estiver usando HTTP, é usar HTTP.SYS . Isso permite que vários processos escutem URLs diferentes na mesma porta. No Server 2003/2008 / Vista / 7 é assim que o IIS funciona, então você pode compartilhar portas com ele. (No XP SP2, HTTP.SYS é compatível, mas IIS5.1 não o usa.)
Outras APIs de alto nível (incluindo WCF) usam HTTP.SYS.
fonte