GNU/Linux >> Belajar Linux >  >> Linux

Mengapa kita mentransmisikan sockaddr_in ke sockaddr saat memanggil bind()?

Tidak, ini bukan hanya konvensi.

sockaddr adalah deskriptor umum untuk segala jenis operasi soket, sedangkan sockaddr_in adalah struct khusus untuk komunikasi berbasis IP (IIRC, "in" adalah singkatan dari "InterNet"). Sejauh yang saya tahu, ini adalah semacam "polimorfisme" :bind() fungsi berpura-pura mengambil struct sockaddr * , tetapi pada kenyataannya, itu akan mengasumsikan bahwa jenis struktur yang sesuai diteruskan; saya. e. yang sesuai dengan jenis soket yang Anda berikan sebagai argumen pertama.


Saya tidak tahu apakah ini sangat relevan untuk pertanyaan ini, tetapi saya ingin memberikan beberapa info tambahan yang dapat membuat typecaste lebih mudah dipahami karena banyak orang yang tidak menghabiskan banyak waktu dengan C bingung melihat typecaste seperti itu.

Saya menggunakan macOS , jadi saya mengambil contoh berdasarkan file header dari sistem saya.

struct sockaddr didefinisikan sebagai berikut:

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 didefinisikan sebagai berikut:

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];
};

Mulai dari yang paling dasar, pointer hanya berisi alamat. Jadi struct sockaddr * dan struct sockaddr_in * hampir sama. Keduanya hanya menyimpan alamat. Satu-satunya perbedaan yang relevan adalah bagaimana kompiler memperlakukan objek mereka.

Jadi ketika Anda mengatakan (struct sockaddr *) &name , Anda hanya menipu kompiler dan mengatakan bahwa alamat ini menunjuk ke struct sockaddr ketik.

Jadi katakanlah pointer menunjuk ke lokasi 1000 . Jika struct sockaddr * menyimpan alamat ini, ia akan mempertimbangkan memori dari 1000 ke sizeof(struct sockaddr) memiliki anggota sesuai definisi struktur. Jika struct sockaddr_in * menyimpan alamat yang sama yang akan dianggap sebagai memori dari 1000 ke sizeof(struct sockaddr_in) .

Saat Anda mengetik pointer itu, itu akan mempertimbangkan urutan byte yang sama hingga sizeof(struct sockaddr) .

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

Sekarang jika saya mengakses a->sa_len , kompiler akan mengakses dari lokasi 1000 ke sizeof(__uint8_t) yang ukuran bytenya sama dengan sockaddr_in . Jadi ini harus mengakses urutan byte yang sama.

Pola yang sama untuk sa_family .

Setelah itu ada array karakter 14 byte di struct sockaddr yang menyimpan data dari in_port_t sin_port (typedef 'd 16 bit unsigned integer =2 bytes ), struct in_addr sin_addr (hanya alamat ipv4 32 bit =4 byte) dan char sin_zero[8] (8 byte). 3 ini dijumlahkan menjadi 14 byte.

Sekarang ketiganya disimpan dalam larik karakter 14 byte ini dan kita dapat mengakses salah satu dari ketiganya dengan mengakses indeks yang sesuai dan mengetikkannya lagi.

jawaban user529758 sudah menjelaskan alasan melakukan ini.


Ini karena bind dapat mengikat jenis soket lain selain soket IP, misalnya soket domain Unix, yang bertipe sockaddr_un. Alamat untuk soket AF_INET memiliki host dan porta sebagai alamatnya, sedangkan soket AF_UNIX memiliki jalur sistem file.


Linux
  1. Mengapa OpenStack melaporkan tipe Hypervisor sebagai QEMU ketika libvirt_type adalah KVM?

  2. Mengapa Sinkronisasi Sangat Penting Saat Membuat Stik Usb Linux yang Dapat Di-boot?

  3. Mengapa Nilai Inode Berubah Saat Kami Mengedit Di Editor “vi”?

  1. Kapan Dan Mengapa Saya Harus Menggunakan Pembaruan Apt-get?

  2. Mengapa Garis Miring Balik Tunggal Ditampilkan Saat Menggunakan Kutipan?

  3. Kapan dan Mengapa Menggunakan Docker

  1. Mengapa pipa shell ini keluar?

  2. Mengapa saya mendapatkan Izin Ditolak saat menjalankan ssh-add?

  3. Mengapa LXC ketika ada linux-vserver?