Kısmi okumalarda unix akışı yardımcı verileriyle ne olur?


18

Bu yüzden unix-stream yardımcı verileri hakkında çok fazla bilgi okudum, ancak tüm belgelerde eksik olan bir şey, kısmi bir okuma olduğunda ne olması gerekiyor?

24 baytlık bir arabellek için aşağıdaki iletileri aldığımı varsayalım

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)

İlk recvmsg çağrısı, tüm msg1 (ve msg2'nin bir parçası? mesajın verilerle ne yapmamı söylediğini bildiğimde? 20 bayt msg1'den kurtarır ve sonra tekrar recvmsg'yi çağırırsam, msg3 ve msg4'ü aynı anda teslim eder mi? Msg3 ve msg4'ten gelen yardımcı veriler kontrol mesajı yapısında birleştiriliyor mu?

Bunu deneysel olarak bulmak için test programları yazarken, yardımcı verilerin akış bağlamında nasıl davrandığına dair belgeler arıyorum . Üzerinde resmi bir şey bulamam tuhaf görünüyor.


Bu test programından aldığım deneysel bulgularımı buraya ekleyeceğim:

https://github.com/nrdvana/daemonproxy/blob/master/src/ancillary_test.c

Linux 3.2.59, 3.17.6

Görünüşe göre bu recvmsg çağrısı sırasında önceden yardımcı ek yükün sağlanması gerekmediği sürece Linux yardımcı mesajların bazı kısımlarını diğer mesajların sonuna ekleyecektir. Bir iletinin yardımcı verileri iletildikten sonra, bir sonraki yardımcı veri iletisini başlatmak yerine kısa bir okuma döndürür. Yani, yukarıdaki örnekte, aldığım okumalar:

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, Linux'tan daha fazla hizalama sağlar ve yardımcı veriler içeren bir mesajın başlamasından hemen önce kısa bir okuma sağlar. Ancak, yardımcı bir mesajın sonuna yardımcı olmayan bir mesaj ekleyecektir. Yani BSD için, tamponunuzun yardımcı mesajdan daha büyük olması durumunda, neredeyse paket benzeri davranışlar elde edersiniz. Aldığım okumalar:

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]

YAPMAK:

Hala gibi nasıl vb yaşlı Linux, iOS Solaris, olur nasıl bilmeli ve bu misiniz olabilir gelecekte ne beklenebilir.


Akışları ve paketleri karıştırmayın, bir akışta verilerin gönderildiği yığınlarla gönderileceğinin garantisi yoktur, bunun için akış tabanlı değil, paket tabanlı bir protokole ihtiyacınız olacaktır.
ctrl-alt-delor

bu yüzden bu soruyu soruyorum
M Conrad

Sipariş korunmalıdır. Akışlar bunu yapar. Engelleme okuması 0 değerini döndürürse, akışın sonu olur. Başka bir sayı döndürürse, daha fazlası olabilir, öğrenmek için en az bir tane daha okumalısınız. İleti1, ileti2 vb. Diye bir şey yoktur. İleti sınırlayıcısı iletilmez. İhtiyacınız varsa bunu protokolünüze eklemeniz gerekir.
ctrl-alt-delor

1
Özellikle, bir metin akışı protokolü var ve bir metin satırı ile bir dosya tanımlayıcı geçen bir komut ekliyorum. Kod düzgün yazmak için bu yardımcı verilerin mesaj metni ile ilgili olarak hangi sırada alındığını bilmek gerekir.
M Conrad

1
@MConrad: POSIX.1g belirtiminin bir kopyasını almaya çalışacağım. Orada açıkça yazılmamışsa, uygulamaya özel bir davranış bekleyebilirsiniz.
Laszlo Valko

Yanıtlar:


1

Yardımcı veriler, segmentteki (eğer varsa) ilk normal veri sekizliği ile birlikte sıraya alınmış gibi alınır.

- POSIX.1-2017

Sorunuzun geri kalanı için, işler biraz kıllı olur.

... Bu bölümün amaçları açısından, bir datagram, bir kaydı sonlandıran ve özel bir yardımcı veri türü olarak bir kaynak adresi içeren bir veri segmenti olarak kabul edilir.

Protokol tarafından veri sokete iletilirken veri segmentleri kuyruğa yerleştirilir. Normal veri segmentleri, teslim edildikleri sırada kuyruğun sonuna yerleştirilir. Yeni bir segment, önceki segmentle aynı türde veriler içeriyorsa ve yardımcı veriler içermiyorsa ve önceki segment bir kaydı sonlandırmazsa, segmentler mantıksal olarak tek bir segmentte birleştirilir ...

Bir alma işlemi asla birden fazla segmentten veri veya yardımcı veri döndürmez.

Böylece modern BSD soketleri bu ekstraktla tam olarak eşleşir. Bu şaşırtıcı değil :-).

POSIX standardının UNIX'ten sonra ve BSD ve Sistem V gibi bölünmelerden sonra yazıldığını unutmayın. Ana hedeflerden biri, mevcut davranış aralığını anlamaya yardımcı olmak ve mevcut özelliklerde daha da fazla bölünmeyi önlemekti.

Linux, BSD koduna başvurulmadan uygulandı. Burada farklı davranıyor gibi görünüyor.

  1. Seni doğru okursanız, yeni bölüm ne zaman Linux ayrıca "segmentleri" birleşiyorsa gibi geliyor yapar yardımcı verileri içerir, ancak önceki segmenti yok.

  2. "Linux bu recvmsg çağrısı sırasında herhangi bir ön ek yükün sağlanması gerekmediği sürece, yan iletilerin bazı bölümlerini diğer iletilerin sonuna ekleyecektir" ifadesi standart tarafından tam olarak açıklanmamış gibi görünmektedir. Olası açıklamalardan biri yarış koşulunu içerebilir. Bir "segment" in bir kısmını okursanız, yardımcı verileri alırsınız. Belki de Linux bunu, segmentin geri kalanının artık yan veriler dahil sayılmadığı anlamına geliyordu! Bu nedenle, yeni bir segment alındığında, standarda göre veya yukarıdaki fark 1'e göre birleştirilir.

Maksimum taşınabilir bir program yazmak istiyorsanız, bu alandan tamamen kaçınmalısınız. Yardımcı verileri kullanırken, datagram soketlerinin kullanılması çok daha yaygındır . Teknik olarak POSIX gibi bir şey sağlamayı amaçlayan tüm garip platformlarda çalışmak istiyorsanız, sorunuz karanlık ve test edilmemiş bir köşeye giriyor gibi görünüyor.


Linux'un hala bazı önemli ilkeleri izlediğini iddia edebilirsiniz:

  1. "Yardımcı veriler, segmentteki ilk normal veri sekizli ile birlikte sıraya alınmış gibi alınır".
  2. Yardımcı veriler, koyduğunuz gibi asla "birleştirilmez".

Ancak, Linux davranışının özellikle yararlı olduğuna ikna olmadım BSD davranışıyla karşılaştırdığınızda . Açıkladığınız programın Linux'a özgü bir geçici çözüm eklemesi gerekecek gibi görünüyor. Ve Linux'un neden bunu yapmanızı beklediğine dair bir gerekçe bilmiyorum.

Linux çekirdek kodunu yazarken mantıklı görünebilir, ancak herhangi bir program tarafından test edilmeden veya kullanılmadan.

Ya da çoğunlukla bu alt küme altında çalışan bazı program kodları tarafından kullanılabilir , ancak prensipte son durum "hataları" veya yarış koşulları olabilir.

Linux davranışı ve kullanım amacını anlayamıyorsanız, bunun Linux'ta "karanlık, denenmemiş bir köşe" olarak ele alınacağını düşünüyorum.


Ayrıntılı inceleme için teşekkürler! Burada paket servisi olan restoran güvenli bir şekilde bu iki tampon (her biri veri bölümü ve yardımcı bölümü ile) ele olduğunu düşünüyorum; İlk okumada dosya tanımlayıcıları alırsam ve mesaja ait değilse, ancak başka bir mesaj başlarsa, bir sonraki okuma da yardımcı veriler içeriyorsa, kesinlikle ilk yardımcı yüke sahip veri mesajımın sonunu bulacağım anlamına gelir o ikinci okumada. İleri ve geri dönerek, her zaman ilk baytın konumuna göre mesajı yük ile eşleştirebilmeliyim.
M Conrad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.