GNU/Linux >> Linux Esercitazione >  >> Linux

Scopo dell'indirizzo sendto per il socket raw C?

Scrittura al socket con send fallisce, dicendomi che devo specificare un indirizzo.

Fallisce, perché send() la funzione può essere utilizzata solo su connesso prese (come indicato qui). Di solito useresti send() per la comunicazione TCP (orientata alla connessione) e sendto() può essere utilizzato per inviare datagrammi UDP (senza connessione).

Poiché si desidera inviare pacchetti "ping", o più correttamente datagrammi ICMP, che sono chiaramente senza connessione, è necessario utilizzare il sendto() funzione.

Sembra nessuno dei campi extra in sendto sono effettivamente utilizzati in misura maggiore. Quindi, c'è un motivo tecnico per cui devo usare sendto invece di send o è solo una svista nell'API?

Risposta breve:

Quando non sei autorizzato a usare send() , rimane solo un'opzione, chiamata sendto() .

Risposta lunga:

Non è solo una svista nell'API. Se vuoi inviare un datagramma UDP usando un normale socket (es. SOCK_DGRAM ), sendto() ha bisogno delle informazioni sull'indirizzo di destinazione e sulla porta, che hai fornito nella struct sockaddr_in , Giusto? Il kernel inserirà tali informazioni nell'intestazione IP risultante, poiché la struct sockaddr_in è l'unico luogo in cui hai specificato chi sarà il destinatario. O in altre parole:in questo caso il kernel deve prendere le informazioni di destinazione dalla tua struttura poiché non fornisci un'intestazione IP aggiuntiva.

Perché sendto() non è utilizzato solo per UDP ma anche per i raw socket, deve essere una funzione più o meno "generica" ​​in grado di coprire tutti i diversi casi d'uso, anche quando alcuni parametri come il numero di porta non sono rilevanti/utilizzati alla fine.

Ad esempio, utilizzando IPPROTO_RAW (che implica automaticamente IP_HDRINCL ), mostri la tua intenzione di voler creare l'intestazione IP da solo. Così gli ultimi due argomenti di sendto() sono in realtà informazioni ridondanti, perché sono già incluse nel buffer di dati che passi a sendto() come secondo argomento. Nota che, anche quando usi IP_HDRINCL con il tuo raw socket, il kernel compilerà l'indirizzo sorgente e il checksum del tuo datagramma IP se imposti i campi corrispondenti a 0 .

Se vuoi scrivere il tuo programma ping, puoi anche cambiare l'ultimo argomento nel tuo socket() funzione da IPPROTO_RAW a IPPROTO_ICMP e lascia che il kernel crei l'intestazione IP per te, così hai una cosa in meno di cui preoccuparti. Ora puoi facilmente vedere come i due sendto() -parametri *dest_addr e addrlen diventa di nuovo significativo perché è l'unico posto in cui fornisci un indirizzo di destinazione.

Il linguaggio e le API sono molto vecchi e sono cresciuti nel tempo. Alcune API possono sembrare strane dal punto di vista odierno, ma non è possibile modificare le vecchie interfacce senza interrompere un'enorme quantità di codice esistente. A volte devi solo abituarti a cose che sono state definite/progettate molti anni o decenni fa.

Spero di aver risposto alla tua domanda.


Il send() chiamata è usata quando i socket sono in un SOCK_STREAM TCP stato connesso.

Dalla pagina man:

la chiamata send() può essere utilizzata solo quando il socket è in uno stato connesso (in modo che il destinatario previsto sia noto).

Poiché la tua applicazione ovviamente non si connette a nessun altro socket, non possiamo aspettarci send() lavorare.


Linux
  1. ppl – Una rubrica da riga di comando per Linux

  2. Lo scopo della parola chiave "do" in Bash For Loops?

  3. Comando per determinare l'IP pubblico?

  4. Considerazioni sulla migrazione a un server cloud per uso generico o I/O

  5. Ottenere l'indirizzo MAC

Configurazioni di indirizzi IP statici e dinamici per DHCP

Indirizzo sorgente di controllo per le query Whois?

I 10 migliori strumenti di gestione degli indirizzi IP per Linux

Indirizzo IP statico con NetworkManager per Fedora

Devo usare un secondo indirizzo IP/dedicato per SSH?

Come inviare un messaggio di posta non elaborato su Linux?