Jawaban atas pertanyaan-pertanyaan ini bervariasi tergantung pada apakah Anda menggunakan soket aliran ( SOCK_STREAM
) atau soket datagram ( SOCK_DGRAM
) - dalam TCP / IP, yang pertama sesuai dengan TCP dan yang terakhir dengan UDP.
Bagaimana Anda tahu seberapa besar untuk membuat buffer diteruskan recv()
?
SOCK_STREAM
: Tidak terlalu penting. Jika protokol Anda bersifat transaksional / interaktif, pilih saja ukuran yang dapat menampung pesan / perintah individu terbesar yang Anda harapkan (3000 kemungkinan baik-baik saja). Jika protokol Anda mentransfer data massal, maka buffer yang lebih besar bisa lebih efisien - aturan praktis yang baik hampir sama dengan kernel menerima ukuran buffer dari socket (seringkali sekitar 256kB).
SOCK_DGRAM
: Gunakan penyangga yang cukup besar untuk menampung paket terbesar yang pernah dikirim protokol tingkat aplikasi Anda. Jika Anda menggunakan UDP, maka secara umum protokol tingkat aplikasi Anda seharusnya tidak mengirim paket yang lebih besar dari sekitar 1400 byte, karena mereka pasti perlu difragmentasi dan disusun kembali.
Apa yang terjadi jika recv
mendapat paket yang lebih besar dari buffer?
SOCK_STREAM
: Pertanyaannya tidak masuk akal, karena soket aliran tidak memiliki konsep paket - mereka hanya aliran byte yang berkelanjutan. Jika ada lebih banyak byte yang tersedia untuk dibaca daripada ruang buffer Anda, maka mereka akan diantrekan oleh OS dan tersedia untuk panggilan Anda selanjutnya recv
.
SOCK_DGRAM
: Bytes yang berlebihan dibuang.
Bagaimana saya bisa tahu jika saya telah menerima seluruh pesan?
SOCK_STREAM
: Anda perlu membangun beberapa cara untuk menentukan end-of-message ke dalam protokol tingkat aplikasi Anda. Biasanya ini adalah awalan panjang (mulai setiap pesan dengan panjang pesan) atau pembatas akhir pesan (yang mungkin hanya berupa baris baru dalam protokol berbasis teks, misalnya). Opsi ketiga, yang kurang digunakan, adalah untuk mengamanatkan ukuran tetap untuk setiap pesan. Kombinasi opsi ini juga dimungkinkan - misalnya, header ukuran tetap yang menyertakan nilai panjang.
SOCK_DGRAM
: recv
Panggilan tunggal selalu mengembalikan datagram tunggal.
Apakah ada cara saya dapat membuat buffer tidak memiliki jumlah ruang yang tetap, sehingga saya dapat terus menambahkannya tanpa takut kehabisan ruang?
Tidak. Namun, Anda dapat mencoba mengubah ukuran buffer menggunakan realloc()
(jika awalnya dialokasikan dengan malloc()
atau calloc()
, yaitu).
recv
ke buffer mengikuti pesan parsial. Anda tidak boleh menggunakanstrstr()
buffer mentah yang diisi olehrecv()
- tidak ada jaminan bahwa itu berisi nul-terminator, jadi itu bisa menyebabkanstrstr()
crash.recv()
untuk menulis lebih banyak byte daripada ada ruang yang tersisa.Untuk protokol streaming seperti TCP, Anda dapat mengatur buffer dengan ukuran apa pun. Yang mengatakan, nilai-nilai umum yang merupakan kekuatan 2 seperti 4096 atau 8192 direkomendasikan.
Jika ada lebih banyak data maka apa buffer Anda, itu hanya akan disimpan dalam kernel untuk panggilan Anda selanjutnya
recv
.Ya, Anda dapat terus menumbuhkan buffer Anda. Anda dapat melakukan recv ke tengah buffer mulai dari offset
idx
, Anda akan melakukan:sumber
Jika Anda memiliki
SOCK_STREAM
soket,recv
dapatkan "hingga 3000 byte pertama" dari stream. Tidak ada panduan yang jelas tentang seberapa besar membuat buffer: satu-satunya waktu Anda tahu seberapa besar aliran, adalah ketika semuanya selesai ;-).Jika Anda memiliki
SOCK_DGRAM
soket, dan datagram lebih besar dari buffer,recv
isi buffer dengan bagian pertama datagram, mengembalikan -1, dan set errno ke EMSGSIZE. Sayangnya, jika protokolnya adalah UDP, ini berarti seluruh datagram hilang - bagian dari alasan mengapa UDP disebut sebagai protokol yang tidak dapat diandalkan (saya tahu bahwa ada protokol datagram yang dapat diandalkan tetapi mereka tidak terlalu populer - saya tidak bisa nama satu dalam keluarga TCP / IP, meskipun mengetahui yang terakhir dengan cukup baik ;-).Untuk menumbuhkan buffer secara dinamis, alokasikan awalnya dengan
malloc
dan gunakanrealloc
sesuai kebutuhan. Tapi itu tidak akan membantu Andarecv
dari sumber UDP, sayangnya.sumber
Untuk
SOCK_STREAM
soket, ukuran buffer tidak terlalu penting, karena Anda hanya menarik beberapa byte yang menunggu dan Anda dapat mengambil lebih banyak di panggilan berikutnya. Pilih saja ukuran buffer apa pun yang Anda mampu.Untuk
SOCK_DGRAM
soket, Anda akan mendapatkan bagian yang pas dari pesan tunggu dan sisanya akan dibuang. Anda bisa mendapatkan ukuran datagram tunggu dengan ioctl berikut:Atau Anda dapat menggunakan
MSG_PEEK
danMSG_TRUNC
menandairecv()
panggilan untuk mendapatkan ukuran datagram yang menunggu.Anda perlu
MSG_PEEK
mengintip (tidak menerima) pesan tunggu - recv mengembalikan ukuran sebenarnya, bukan terpotong; dan Anda tidak perluMSG_TRUNC
meluap buffer Anda saat ini.Maka Anda bisa saja
malloc(size)
buffer nyata danrecv()
datagram.sumber
malloc()
untuk buffer 64KB makaMSG_TRUNC
tidak perlu?SOCK_DGRAM
bukan hanya UDP.Tidak ada jawaban mutlak untuk pertanyaan Anda, karena teknologi selalu terikat pada implementasi spesifik. Saya berasumsi Anda berkomunikasi dalam UDP karena ukuran buffer yang masuk tidak membawa masalah pada komunikasi TCP.
Menurut RFC 768 , ukuran paket (termasuk header) untuk UDP dapat berkisar dari 8 hingga 65.515 byte. Jadi ukuran gagal-bukti untuk buffer yang masuk adalah 65 507 byte (~ 64KB)
Namun, tidak semua paket besar dapat diarahkan dengan benar oleh perangkat jaringan, lihat diskusi yang ada untuk informasi lebih lanjut:
Berapa ukuran optimal paket UDP untuk throughput maksimum?
Apa Ukuran Paket UDP Aman terbesar di Internet
sumber
16kb hampir benar; jika Anda menggunakan gigabit ethernet, setiap paket bisa berukuran 9 kb.
sumber