Apa yang terjadi dengan data tambahan unix stream pada pembacaan parsial?


18

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.


Jangan bingung aliran dan paket, dalam aliran tidak ada jaminan bahwa data akan dikirim dalam potongan yang sama dengan yang dikirim, untuk ini Anda akan memerlukan protokol berbasis paket, bukan berbasis aliran.
ctrl-alt-delor

itulah tepatnya mengapa saya mengajukan pertanyaan ini
M Conrad

Perintah itu harus dipertahankan. Itulah yang dilakukan stream. Jika pembacaan pemblokiran menghasilkan 0, maka itu adalah akhir dari aliran. Jika mengembalikan nomor lain maka mungkin ada lebih banyak, Anda harus melakukan setidaknya satu bacaan lagi untuk mengetahuinya. Tidak ada yang namanya message1, message2 dll. Tidak ada pembatas pesan yang dikirimkan. Anda harus menambahkan ini ke protokol Anda, jika Anda membutuhkannya.
ctrl-alt-delor

1
Secara khusus, saya memiliki protokol aliran teks dan saya menambahkan perintah yang melewati deskriptor file dengan baris teks. Saya perlu tahu urutan apa data tambahan ini diterima sehubungan dengan teks pesan untuk menulis kode dengan benar.
M Conrad

1
@MConrad: Saya akan mencoba untuk mendapatkan salinan spesifikasi POSIX.1g. Jika tidak ditulis secara eksplisit di sana, maka Anda mungkin mengharapkan perilaku khusus implementasi.
Laszlo Valko

Jawaban:


1

Data tambahan diterima seolah-olah itu antri bersama dengan oktet data normal pertama di segmen (jika ada).

- POSIX.1-2017

Untuk sisa pertanyaan Anda, segalanya menjadi sedikit berbulu.

... Untuk keperluan bagian ini, datagram dianggap sebagai segmen data yang mengakhiri rekaman, dan itu termasuk alamat sumber sebagai tipe khusus dari data tambahan.

Segmen data ditempatkan ke dalam antrian saat data dikirimkan ke soket oleh protokol. Segmen data normal ditempatkan di akhir antrian saat dikirimkan. Jika segmen baru berisi tipe data yang sama dengan segmen sebelumnya dan tidak menyertakan data tambahan, dan jika segmen sebelumnya tidak menghentikan catatan, maka segmen tersebut secara logis akan digabung menjadi satu segmen ...

Operasi penerimaan tidak boleh mengembalikan data atau data tambahan dari lebih dari satu segmen.

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.

  1. Jika saya membaca Anda dengan benar, kedengarannya seperti Linux juga penggabungan "segmen" ketika segmen baru tidak termasuk data pendukung, tetapi segmen sebelumnya tidak.

  2. 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:

  1. "Data tambahan diterima seolah-olah sedang antri bersama dengan oktet data normal pertama di segmen".
  2. Data tambahan tidak pernah "digabungkan", seperti yang Anda katakan.

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.


Terima kasih untuk ulasan mendalam! Saya pikir takeaway di sini adalah bahwa saya dapat dengan aman menangani ini dengan dua buffer (masing-masing dengan bagian data dan bagian tambahan); Jika saya menerima deskriptor file pada bacaan pertama dan itu bukan milik pesan, tetapi pesan lain dimulai, maka jika bacaan berikutnya juga berisi data tambahan itu berarti saya pasti akan menemukan akhir pesan data saya memiliki muatan tambahan tambahan pertama di baca kedua itu. Bergantian bolak-balik, saya harus selalu dapat mencocokkan pesan dengan payload berdasarkan lokasi byte pertama.
M Conrad
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.