Vamos rever rapidamente os arquivos do dispositivo: No Linux, os programas aplicativos comunicam as operações rad e write ao kernel por meio de descritores de arquivos . Isso funciona muito bem para arquivos, e descobriu-se que a mesma API poderia ser usada para dispositivos de caracteres que produzem e consomem fluxos de caracteres e bloqueiam dispositivos que lêem e escrevem blocos de tamanho fixo em um endereço de acesso aleatório, apenas fingindo que estes também são arquivos.
Mas era necessário um caminho para configurar esses dispositivos (definir taxas de transmissão etc.) e, para isso, a chamada ioctl foi inventada. Ele apenas passa uma estrutura de dados que é específica para o dispositivo e o tipo de controle de E / S usado para o kernel, e retorna os resultados na mesma estrutura de dados, por isso é uma API extensível muito genérica e pode ser usada para muitas coisas .
Agora, como as operações de rede se encaixam? Um típico aplicativo de servidor de rede deseja ligar a algum endereço de rede, escutar em uma determinada porta (por exemplo, 80 para HTTP ou 22 para ssh) e se um cliente > conecta , ele quer enviar dados para e receber dados deste cliente. E as operações duplas para o cliente.
Não é óbvio como se encaixa isso nas operações de arquivos (embora isso possa ser feito, veja Plano 9 ), é por isso que os projetistas do UNIX inventaram uma nova API: sockets . Você pode encontrar detalhes na seção 2 man pages para socket
, bind
, listen
, connect
, send
e recv
. Observe que, embora seja diferente da API de E / S de arquivos, a chamada socket
, no entanto, também retorna um descritor de arquivo. Existem inúmeros tutoriais sobre como usar sockets na web, google um pouco.
Até agora tudo isso é puro UNIX, ninguém falava sobre interfaces de rede na época em que os soquetes eram inventados. E como essa API é realmente antiga, ela é definida para uma variedade de protocolos de rede além do protocolo da Internet (observe as AF_*
constantes), embora apenas algumas delas sejam suportadas no Linux.
Mas como os computadores começaram a receber várias placas de rede, foi necessária alguma abstração para isso. No Linux, essa é a interface de rede (NI). Ele não é usado apenas para uma peça de hardware, mas também para vários túneis, terminais de aplicativos do usuário que funcionam como túneis como o OpenVPN, etc. Conforme explicado, a API do soquete não é baseada em arquivos (especiais) e independente do sistema de arquivos. Da mesma forma, as interfaces de rede também não aparecem no sistema de arquivos. No entanto, os NIs são disponibilizados no sistema de arquivos /proc
e /sys
(assim como outros ajustáveis de rede).
Uma NI é simples, uma abstração do kernel de um nó de extremidade onde os pacotes de rede entram e saem do kernel. Soquetes, por outro lado, são usados para comunicar pacotes com aplicativos. Nenhum socket precisa estar envolvido com o processamento de um pacote. Por exemplo, quando o encaminhamento está ativado, um pacote pode entrar em um NI e sair em outro. Nesse sentido, soquetes e interfaces de rede são totalmente independentes.
Mas tinha que haver uma maneira de configurar os NIs, assim como você precisava de uma maneira de configurar dispositivos de blocos e caracteres. E como os sockets já retornavam um descritor de arquivo, era um pouco lógico permitir apenas um ioctl
nesse descritor de arquivo. Essa é a interface do netdevice que você vinculou.
Existem muitos outros abusos de chamadas do sistema de maneira semelhante, por exemplo, para filtragem de pacotes, captura de pacotes, etc.
Tudo isso cresceu peça após peça e não é particularmente lógico em muitos lugares. Se tivesse sido desenhado de uma só vez, provavelmente poderia ter feito uma API mais ortogonal.