Jadi saya sudah membaca banyak informasi tentang data tambahan unix-stream, tetapi satu hal yang hilang dari semua dokumentasi adalah apa yang seharusnya terjadi ketika ada sebagian membaca?
Misalkan saya menerima pesan berikut ke buffer 24 byte
msg1 [20 byes] (no ancillary data)
msg2 [7 bytes] (2 file descriptors)
msg3 [7 bytes] (1 file descriptor)
msg4 [10 bytes] (no ancillary data)
msg5 [7 bytes] (5 file descriptors)
Panggilan pertama ke recvmsg, saya mendapatkan semua msg1 (dan bagian dari msg2? Apakah OS akan pernah melakukan itu?) Jika saya mendapatkan bagian dari msg2, apakah saya mendapatkan data tambahan segera, dan perlu menyimpannya untuk dibaca selanjutnya ketika saya tahu apa yang sebenarnya dikatakan oleh pesan kepada saya tentang data tersebut? Jika saya membebaskan 20 byte dari msg1 dan kemudian memanggil recvmsg lagi, akankah ia mengirimkan pesan ps3 dan pesan secara bersamaan? Apakah data tambahan dari msg3 dan msg4 disatukan dalam struct pesan kontrol?
Sementara saya dapat menulis program pengujian untuk mengetahui hal ini secara eksperimental, saya mencari dokumentasi tentang bagaimana data tambahan berperilaku dalam konteks streaming. Tampaknya aneh bahwa saya tidak dapat menemukan sesuatu yang resmi di situ.
Saya akan menambahkan temuan percobaan saya di sini, yang saya dapatkan dari program tes ini:
https://github.com/nrdvana/daemonproxy/blob/master/src/ancillary_test.c
Linux 3.2.59, 3.17.6
Tampaknya Linux akan menambahkan bagian-bagian dari pesan tambahan di akhir pesan lainnya selama tidak ada muatan tambahan yang perlu dikirimkan selama panggilan ini ke recvmsg. Setelah data tambahan satu pesan dikirimkan, itu akan mengembalikan bacaan singkat daripada memulai pesan data tambahan berikutnya. Jadi, dalam contoh di atas, bacaan yang saya dapatkan adalah:
recv1: [24 bytes] (msg1 + partial msg2 with msg2's 2 file descriptors)
recv2: [10 bytes] (remainder of msg2 + msg3 with msg3's 1 file descriptor)
recv3: [17 bytes] (msg4 + msg5 with msg5's 5 file descriptors)
recv4: [0 bytes]
BSD 4.4, 10.0
BSD menyediakan lebih banyak perataan daripada Linux, dan memberikan bacaan singkat segera sebelum memulai pesan dengan data tambahan. Tapi, itu akan dengan senang hati menambahkan pesan yang tidak mengandung pendukung sampai akhir dari pesan yang mengandung pendukung. Jadi untuk BSD, sepertinya jika buffer Anda lebih besar dari pesan tambahan, Anda mendapatkan perilaku hampir seperti paket. Bacaan yang saya dapatkan adalah:
recv1: [20 bytes] (msg1)
recv2: [7 bytes] (msg2, with msg2's 2 file descriptors)
recv3: [17 bytes] (msg3, and msg4, with msg3's 1 file descriptor)
recv4: [7 bytes] (msg5 with 5 file descriptors)
recv5: [0 bytes]
MELAKUKAN:
Masih ingin tahu bagaimana hal itu terjadi pada Linux yang lebih lama, iOS, Solaris, dll, dan bagaimana hal itu bisa diharapkan terjadi di masa depan.
sumber
Jawaban:
Untuk sisa pertanyaan Anda, segalanya menjadi sedikit berbulu.
Jadi soket BSD modern sama persis dengan ekstrak ini. Ini tidak mengherankan :-).
Ingat standar POSIX ditulis setelah UNIX, dan setelah pemisahan seperti BSD vs Sistem V. Salah satu tujuan utama adalah untuk membantu memahami rentang perilaku yang ada, dan mencegah lebih banyak perbedaan dalam fitur yang ada.
Linux diimplementasikan tanpa mengacu pada kode BSD. Tampaknya berperilaku berbeda di sini.
Jika saya membaca Anda dengan benar, kedengarannya seperti Linux juga penggabungan "segmen" ketika segmen baru tidak termasuk data pendukung, tetapi segmen sebelumnya tidak.
Maksud Anda bahwa "Linux akan menambahkan bagian-bagian dari pesan tambahan di akhir pesan lainnya selama tidak ada muatan tambahan yang perlu dikirim selama panggilan ini ke recvmsg", tampaknya tidak sepenuhnya dijelaskan oleh standar. Satu penjelasan yang mungkin akan melibatkan kondisi ras. Jika Anda membaca bagian dari "segmen", Anda akan menerima data tambahan. Mungkin Linux menafsirkan ini sebagai berarti sisa segmen tidak lagi dianggap sebagai data tambahan! Jadi, ketika sebuah segmen baru diterima, itu digabung - baik sesuai standar, atau sesuai perbedaan 1 di atas.
Jika Anda ingin menulis program portabel yang maksimal, Anda harus menghindari area ini sama sekali. Saat menggunakan data tambahan, jauh lebih umum untuk menggunakan soket datagram . Jika Anda ingin bekerja pada semua platform aneh yang secara teknis bercita-cita untuk menyediakan sesuatu seperti POSIX, pertanyaan Anda tampaknya merambah ke sudut yang gelap dan belum teruji.
Anda bisa berpendapat Linux masih mengikuti beberapa prinsip penting:
Namun, saya tidak yakin perilaku Linux sangat berguna , ketika Anda membandingkannya dengan perilaku BSD. Sepertinya program yang Anda jelaskan perlu menambahkan solusi khusus Linux. Dan saya tidak tahu alasan mengapa Linux mengharapkan Anda melakukan itu.
Mungkin terlihat masuk akal ketika menulis kode kernel Linux, tetapi tanpa pernah diuji atau dilakukan oleh program apa pun.
Atau mungkin dilakukan oleh beberapa kode program yang sebagian besar berfungsi di bawah subset ini, tetapi pada prinsipnya dapat memiliki "bug" kasus tepi atau kondisi ras.
Jika Anda tidak dapat memahami perilaku Linux dan penggunaan yang dimaksudkan, saya pikir itu berpendapat untuk memperlakukan ini sebagai "sudut gelap, belum teruji" di Linux.
sumber