GNU/Linux >> Linux Esercitazione >  >> Linux

Perché lanciamo sockaddr_in a sockaddr quando chiamiamo bind()?

No, non è solo convenzione.

sockaddr è un descrittore generico per qualsiasi tipo di operazione socket, mentre sockaddr_in è una struttura specifica per la comunicazione basata su IP (IIRC, "in" sta per "InterNet"). Per quanto ne so, questo è un tipo di "polimorfismo":il bind() la funzione finge di prendere un struct sockaddr * , ma in realtà presupporrà che sia passato il tipo di struttura appropriato; io. e. uno che corrisponde al tipo di socket che gli dai come primo argomento.


Non so se sia molto rilevante per questa domanda, ma vorrei fornire alcune informazioni extra che potrebbero rendere il typecaste più comprensibile dato che molte persone che non hanno trascorso molto tempo con C confondersi vedendo una tale casta.

Uso macOS , quindi sto prendendo esempi basati su file di intestazione dal mio sistema.

struct sockaddr è definito come segue:

struct sockaddr {
    __uint8_t       sa_len;         /* total length */
    sa_family_t     sa_family;      /* [XSI] address family */
    char            sa_data[14];    /* [XSI] addr value (actually larger) */
};

struct sockaddr_in è definito come segue:

struct sockaddr_in {
    __uint8_t       sin_len;
    sa_family_t     sin_family;
    in_port_t       sin_port;
    struct  in_addr sin_addr;
    char            sin_zero[8];
};

Partendo dalle basi, un puntatore contiene solo un indirizzo. Quindi struct sockaddr * e struct sockaddr_in * sono praticamente la stessa cosa. Entrambi memorizzano solo un indirizzo. L'unica differenza rilevante è il modo in cui il compilatore tratta i propri oggetti.

Quindi quando dici (struct sockaddr *) &name , stai solo ingannando il compilatore e dicendogli che questo indirizzo punta a un struct sockaddr digitare.

Quindi diciamo che il puntatore punta a una posizione 1000 . Se struct sockaddr * memorizza questo indirizzo, considererà la memoria da 1000 a sizeof(struct sockaddr) in possesso dei membri secondo la definizione della struttura. Se struct sockaddr_in * memorizza lo stesso indirizzo che considererà memoria da 1000 a sizeof(struct sockaddr_in) .

Quando hai digitato quel puntatore, considererà la stessa sequenza di byte fino a sizeof(struct sockaddr) .

struct sockaddr *a = &name; // consider &name = 1000

Ora se accedo a a->sa_len , il compilatore accederà dalla posizione 1000 a sizeof(__uint8_t) che è la stessa dimensione in byte del caso di sockaddr_in . Quindi questo dovrebbe accedere alla stessa sequenza di byte.

Lo stesso modello è per sa_family .

Dopodiché c'è un array di caratteri di 14 byte in struct sockaddr che memorizza i dati da in_port_t sin_port (typedef 'd Intero senza segno a 16 bit =2 byte ) , struct in_addr sin_addr (semplicemente un indirizzo ipv4 a 32 bit =4 byte) e char sin_zero[8] (8 byte). Questi 3 sommati danno 14 byte.

Ora questi tre sono memorizzati in questo array di caratteri da 14 byte e possiamo accedere a uno qualsiasi di questi tre accedendo agli indici appropriati e digitandoli di nuovo.

la risposta di user529758 spiega già il motivo per farlo.


Questo perché bind può associare altri tipi di socket rispetto ai socket IP, ad esempio socket di dominio Unix, che hanno sockaddr_un come tipo. L'indirizzo per un socket AF_INET ha l'host e la porta come indirizzo, mentre un socket AF_UNIX ha un percorso del filesystem.


Linux
  1. Perché OpenStack segnala il tipo Hypervisor come QEMU quando libvirt_type è KVM?

  2. Perché il valore dell'inode cambia quando modifichiamo nell'editor "vi"?

  3. Modo rapido per includere un percorso di directory quando si chiama Mv??

  4. Perché viene mostrata una singola barra rovesciata quando si utilizzano le virgolette?

  5. Quando e perché usare Docker

Quando si utilizza os.execlp, perché `python` ha bisogno di `python` come argv[0]

Perché ricevo Autorizzazione negata quando eseguo ssh-add?

Perché il mio Ubuntu è in ritardo durante lo spostamento di Windows?

Perché LXC quando c'è linux-vserver?

Perché non ho l'evidenziazione della sintassi quando sudo vi <filename>?

Perché Swap viene utilizzato quando è rimasta molta memoria libera?