A história completa é "depende do que você quer dizer". Se você gostaria de ouvir exatamente o mesmo IP e porta de um programa existente sobre o qual você não tem controle, então, como outros indicaram, você pode estar sem sorte. Se, no entanto, você:
- Pode ouvir um endereço IP diferente ou
- Tenha algum controle sobre o aplicativo original
então você pode estar interessado no restante deste post.
Mesma porta, endereço IP diferente
Quando um programa usa a chamada de sistema bind (2) para atribuir um endereço para um soquete, esse endereço (no caso de um soquete AF_INET) especifica a porta e o endereço IP. Dois endereços com a mesma porta, mas diferentes endereços IP são diferentes e podem ser atribuídos separadamente sem conflito. Por exemplo, usando socat eu posso vincular a porta 9000 no endereço IP para minha interface de loopback em uma concha:
socat TCP4-LISTEN:9000,bind=127.0.0.1 STDOUT
e liga-se à mesma porta, mas no meu endereço IP externo em outro:
socat TCP4-LISTEN:9000,bind=10.0.2.15 STDOUT
Ambos os processos podem aceitar conexões que entram no endereço IP & porta eles estão ouvindo. Observe, no entanto, que se alguém estiver ouvindo o endereço wildcar 0.0.0.0, você não poderá se vincular a um endereço mais específico, pois o primeiro processo está vinculado a cada IP no sistema.
Mesma porta, mesmo IP
Por padrão, dois processos não podem ligar dois descritores de arquivos diferentes ao mesmo endereço. No Linux, tentar fazer isso resultará em EADDRINUSE sendo retornado de bind(2)
:
socat TCP4-LISTEN:9000,bind=127.0.0.1 STDOUT
2014/11/07 00:10:13 socat[21202] E bind(3, {AF=2 127.0.0.1:9000}, 16): Address already in use
Dada sua pergunta e acompanhamento, acredito que você não tenha muito controle sobre o programa que está usando a porta desejada. Se você fez, no entanto, é possível que um processo tenha uma conexão estabelecida em um endereço IP + porta enquanto outro está escutando no mesmo endereço. Por exemplo, muitos aplicativos de servidor fazem o seguinte:
- Ter um processo principal bind (), listen () e accept () uma conexão
- Bifurque um novo processo para manipular a conexão aceita, com o processo principal voltando para tentar aceitar () quaisquer novas conexões de entrada.
Nesse caso, você veria um processo filho com uma conexão ESTABLISHED na porta e o processo pai com um soquete LISTENing na mesma porta.
Em kernels Linux muito recentes, é possível que dois processos completamente não relacionados se liguem ao mesmo endereço usando a opção de soquete SO_REUSEPORT. Se um processo definir a opção SO_REUSEPORT no soquete, outros processos com o mesmo UID efetivo do primeiro processo também poderão definir a opção SO_REUSEPORT e vincular-se ao mesmo endereço.
Infelizmente, minha versão de socat
parece ter um bug que torna difícil dar um exemplo fácil de TCP; no entanto, forneci um exemplo de programa curto e mal escrito abaixo. Se você executar esse programa como o mesmo usuário em dois shells diferentes, ambos serão vinculados () sem um problema:
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:9000 *:* users:(("bind_tcp_reusep",pid=21254,fd=3))
LISTEN 0 128 127.0.0.1:9000 *:* users:(("bind_tcp_reusep",pid=21253,fd=3))
O objetivo é oferecer às pessoas que escrevem servidores de rede uma nova ferramenta para criar aplicativos que possam lidar com um grande número de conexões simultâneas.
O seguinte artigo do LWN tem uma boa visão geral do caso de uso para esta opção:
link
Assistindo tráfego em uma conexão estabelecida
Como robbat2 mencionou, se você quiser espionar o tráfego existente tcpdump
é a melhor aposta.
Exemplo de programa SO_REUSEPORT
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <errno.h>
int main() {
struct sockaddr_in bind_addr;
struct sockaddr peer_addr;
int optval = 1;
int tcp_socket;
int err;
int addr_len = sizeof(struct sockaddr);
memset(&bind_addr, 0, sizeof(struct sockaddr_in));
memset(&peer_addr, 0, sizeof(struct sockaddr));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(9000);
if (inet_pton(AF_INET, "127.0.0.1", &(bind_addr.sin_addr)) != 1) {
perror("inet_pton");
exit(1);
}
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(tcp_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
err = bind(tcp_socket, (const struct sockaddr *)&bind_addr, sizeof(struct sockaddr));
if (err != 0) {
perror("bind failed");
exit(1);
}
err = listen(tcp_socket, 256);
if (err != 0) {
perror("listen failed");
exit(1);
}
accept(tcp_socket, &peer_addr, &addr_len);
}