Menulis ke soket dengan
send
gagal, memberi tahu saya bahwa saya perlu menentukan alamat.
Gagal, karena send()
fungsi hanya dapat digunakan pada terhubung soket (sebagaimana dinyatakan di sini). Biasanya Anda akan menggunakan send()
untuk komunikasi TCP (berorientasi koneksi) dan sendto()
dapat digunakan untuk mengirim datagram UDP (tanpa koneksi).
Karena Anda ingin mengirim paket "ping", atau lebih tepatnya datagram ICMP, yang jelas tanpa koneksi, Anda harus menggunakan kode sendto()
fungsi.
Sepertinya tidak ada bidang tambahan di
sendto
benar-benar digunakan untuk sebagian besar. Jadi, apakah ada alasan teknis mengapa saya harus menggunakansendto
bukannyasend
atau hanya pengawasan di API?
Jawaban singkat:
Saat Anda tidak diperbolehkan menggunakan send()
, maka hanya tersisa satu pilihan, yang disebut sendto()
.
Jawaban panjang:
Ini bukan hanya pengawasan di API. Jika Anda ingin mengirim datagram UDP dengan menggunakan soket biasa (mis. SOCK_DGRAM
), sendto()
memerlukan informasi tentang alamat dan port tujuan, yang Anda berikan di struct sockaddr_in
, Baik? Kernel akan memasukkan informasi itu ke dalam header IP yang dihasilkan, karena struct sockaddr_in
adalah satu-satunya tempat di mana Anda menentukan siapa yang akan menjadi penerima. Atau dengan kata lain:dalam hal ini kernel harus mengambil info tujuan dari struct Anda karena Anda tidak memberikan header IP tambahan.
Karena sendto()
tidak hanya digunakan untuk UDP tetapi juga soket mentah, itu harus menjadi fungsi yang kurang lebih "umum" yang dapat mencakup semua kasus penggunaan yang berbeda, bahkan ketika beberapa parameter seperti nomor port pada akhirnya tidak relevan/digunakan.
Misalnya dengan menggunakan IPPROTO_RAW
(yang secara otomatis menyiratkan IP_HDRINCL
), Anda menunjukkan niat Anda bahwa Anda ingin membuat header IP Anda sendiri. Demikianlah dua argumen terakhir dari sendto()
sebenarnya informasi yang berlebihan, karena sudah termasuk dalam buffer data yang Anda teruskan ke sendto()
sebagai argumen kedua. Perhatikan bahwa, meskipun Anda menggunakan IP_HDRINCL
dengan soket mentah Anda, kernel akan mengisi alamat sumber dan checksum dari datagram IP Anda jika Anda menyetel kolom yang sesuai ke 0
.
Jika Anda ingin menulis program ping Anda sendiri, Anda juga dapat mengubah argumen terakhir di socket()
Anda fungsi dari IPPROTO_RAW
ke IPPROTO_ICMP
dan biarkan kernel membuat header IP untuk Anda, sehingga Anda tidak perlu khawatir. Sekarang Anda dapat dengan mudah melihat bagaimana kedua sendto()
-parameter *dest_addr
dan addrlen
menjadi signifikan lagi karena itu satu-satunya tempat di mana Anda memberikan alamat tujuan.
Bahasa dan API sudah sangat tua dan telah berkembang seiring waktu. Beberapa API mungkin terlihat aneh dari perspektif saat ini, tetapi Anda tidak dapat mengubah antarmuka lama tanpa merusak banyak kode yang ada. Terkadang Anda hanya perlu membiasakan diri dengan hal-hal yang telah ditentukan/dirancang bertahun-tahun atau beberapa dekade yang lalu.
Semoga itu menjawab pertanyaan Anda.
send()
panggilan digunakan ketika soket berada di TCP SOCK_STREAM
status terhubung.
Dari halaman manual:
panggilan send() hanya dapat digunakan ketika soket dalam keadaan terhubung (sehingga penerima yang dituju diketahui).
Karena aplikasi Anda jelas tidak terhubung dengan soket lain, kami tidak dapat mengharapkan send()
untuk bekerja.