เกิดอะไรขึ้นกับข้อมูลเสริม unix สตรีมในการอ่านบางส่วน?


18

ดังนั้นฉันได้อ่านข้อมูลมากมายเกี่ยวกับข้อมูลเสริมยูนิกซ์ แต่สิ่งหนึ่งที่ขาดหายไปจากเอกสารทั้งหมดคือสิ่งที่ควรจะเกิดขึ้นเมื่อมีการอ่านบางส่วน?

สมมติว่าฉันได้รับข้อความต่อไปนี้ในบัฟเฟอร์ 24 ไบต์

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)

การเรียกครั้งแรกเพื่อ recvmsg ฉันได้รับ msg1 ทั้งหมด (และเป็นส่วนหนึ่งของ msg2 ระบบปฏิบัติการจะทำเช่นนั้นหรือไม่) ถ้าฉันได้รับส่วนหนึ่งของ msg2 ฉันจะได้รับข้อมูลเสริมทันทีและจำเป็นต้องบันทึกไว้สำหรับการอ่านครั้งต่อไป เมื่อฉันรู้ว่าสิ่งที่ข้อความจริงบอกให้ฉันทำกับข้อมูล? หากฉันเพิ่มขนาด 20 ไบต์จาก msg1 แล้วโทร recvmsg อีกครั้งจะส่ง msg3 และ msg4 พร้อมกันหรือไม่ ข้อมูลเสริมจาก msg3 และ msg4 เชื่อมต่อกันในโครงสร้างข้อความควบคุมหรือไม่?

ในขณะที่ฉันสามารถเขียนโปรแกรมทดสอบเพื่อค้นหาสิ่งนี้ฉันกำลังมองหาเอกสารเกี่ยวกับการทำงานของข้อมูลเสริมในบริบทการสตรีม ดูเหมือนว่าแปลกที่ฉันไม่สามารถหาอะไรเป็นทางการเกี่ยวกับเรื่องนี้


ฉันจะเพิ่มผลการทดลองของฉันที่นี่ซึ่งฉันได้จากโปรแกรมทดสอบนี้:

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

Linux 3.2.59, 3.17.6

ปรากฏว่า Linux จะต่อท้ายข้อความที่มีเครื่องหมายเสริมต่อท้ายข้อความอื่น ๆ ตราบใดที่ไม่มีส่วนของข้อมูลเสริมก่อนหน้านี้ที่จำเป็นต้องส่งมอบในระหว่างการเรียกนี้ไปยัง recvmsg เมื่อมีการส่งข้อมูลเสริมของข้อความหนึ่งข้อความจะส่งคืนการอ่านสั้น ๆ แทนที่จะเริ่มข้อความเสริมข้อมูลถัดไป ดังนั้นในตัวอย่างด้านบนการอ่านที่ฉันได้รับคือ:

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 และให้อ่านสั้น ๆ ทันทีก่อนที่จะเริ่มข้อความที่มีข้อมูลเสริม แต่มันจะเพิ่มข้อความที่ไม่มีเครื่องหมายเสริมต่อท้ายข้อความที่มีเครื่องหมายเสริมอย่างมีความสุข ดังนั้นสำหรับ BSD ดูเหมือนว่าหากบัฟเฟอร์ของคุณมีขนาดใหญ่กว่าข้อความที่แสดงว่าคุณได้รับพฤติกรรมเกือบเหมือนแพ็กเก็ต การอ่านที่ฉันได้รับคือ:

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]

ทำ:

ยังต้องการที่จะรู้ว่ามันเกิดขึ้นบนลินุกซ์เก่า, iOS, Solaris, ฯลฯ และวิธีการที่มันอาจจะคาดว่าจะเกิดขึ้นในอนาคต


อย่าสับสนสตรีมและแพ็กเก็ตในสตรีมจะไม่มีการรับประกันว่าข้อมูลจะถูกส่งในกลุ่มเดียวกับที่ส่งไปสำหรับสิ่งนี้คุณจะต้องใช้โปรโตคอลที่เป็นแพ็กเก็ตไม่ใช่สตรีมที่ใช้
ctrl-alt-delor

นั่นเป็นเหตุผลที่ฉันถามคำถามนี้
M Conrad

ควรรักษาลำดับ นั่นคือสิ่งที่สตรีมทำ หากการบล็อกการอ่านส่งคืนค่า 0 แสดงว่าเป็นการสิ้นสุดของสตรีม หากส่งคืนหมายเลขอื่นอาจมีมากกว่าคุณต้องอ่านอย่างน้อยหนึ่งครั้งเพื่อหาคำตอบ ไม่มีสิ่งเช่น message1, message2 เป็นต้นไม่มีตัวคั่นข้อความถูกส่ง คุณต้องเพิ่มสิ่งนี้ลงในโปรโตคอลของคุณหากคุณต้องการ
ctrl-alt-delor

1
โดยเฉพาะฉันมีโปรโตคอลข้อความสตรีมและฉันเพิ่มคำสั่งที่ส่งไฟล์อธิบายด้วยบรรทัดข้อความ ฉันจำเป็นต้องทราบว่าได้รับข้อมูลเสริมใดบ้างที่เกี่ยวข้องกับข้อความของข้อความเพื่อที่จะเขียนรหัสอย่างถูกต้อง
M Conrad

1
@MConrad: ฉันพยายามรับสำเนาข้อกำหนด POSIX.1g หากยังไม่ได้เขียนอย่างชัดเจนคุณอาจคาดหวังว่าจะมีพฤติกรรมการใช้งานเฉพาะ
Laszlo Valko

คำตอบ:


1

ได้รับข้อมูลเสริมราวกับว่ามันถูกจัดคิวพร้อมกับ octet ข้อมูลแรกในกลุ่ม (ถ้ามี)

- POSIX.1-2017

สำหรับคำถามที่เหลือของคุณสิ่งต่าง ๆ มีขนดกเล็กน้อย

... สำหรับจุดประสงค์ของส่วนนี้ดาต้าถือว่าเป็นส่วนข้อมูลที่ยุติการบันทึกและรวมถึงที่อยู่แหล่งที่มาเป็นข้อมูลเสริมประเภทพิเศษ

ส่วนของข้อมูลจะถูกวางลงในคิวเมื่อข้อมูลถูกส่งไปยังซ็อกเก็ตโดยโปรโตคอล กลุ่มข้อมูลปกติจะถูกวางไว้ที่ส่วนท้ายของคิวเมื่อมีการส่งมอบ หากเซ็กเมนต์ใหม่มีข้อมูลประเภทเดียวกันกับเซ็กเมนต์ก่อนหน้านี้และไม่มีข้อมูลเสริมและหากเซ็กเมนต์ก่อนหน้านี้ไม่ได้ยุติการบันทึกเซ็กเมนต์นั้นจะถูกรวมอย่างมีเหตุผลในเซ็กเมนต์เดียว ...

การดำเนินการรับจะไม่ส่งคืนข้อมูลหรือข้อมูลเสริมจากมากกว่าหนึ่งเซ็กเมนต์

ดังนั้นซ็อกเก็ต BSD ที่ทันสมัยตรงกับสารสกัดนี้ ไม่น่าแปลกใจ :-)

โปรดจำไว้ว่ามาตรฐาน POSIX ถูกเขียนขึ้นหลังจาก UNIX และหลังจากแยกเช่น BSD กับ System V หนึ่งในเป้าหมายหลักคือการช่วยให้เข้าใจช่วงของพฤติกรรมที่มีอยู่และป้องกันไม่ให้แยกคุณสมบัติเพิ่มเติมที่มีอยู่

Linux ถูกนำไปใช้โดยไม่มีการอ้างอิงถึงรหัส BSD ดูเหมือนว่ามันจะทำงานแตกต่างกันที่นี่

  1. ถ้าผมอ่านคุณอย่างถูกต้องก็เสียงเหมือนลินุกซ์นอกจากนี้การควบรวม "กลุ่ม" เมื่อกลุ่มใหม่ไม่รวมข้อมูลเสริม แต่ส่วนที่ก่อนหน้านี้ไม่ได้

  2. จุดของคุณที่ "Linux จะต่อท้ายข้อความที่มีเครื่องหมายเสริมต่อท้ายข้อความอื่น ๆ ตราบใดที่ไม่มีส่วนของข้อมูลเสริมก่อนหน้านี้ที่จำเป็นต้องส่งในระหว่างการเรียกนี้ไปยัง recvmsg" ดูเหมือนจะไม่ได้อธิบายอย่างสมบูรณ์ตามมาตรฐาน คำอธิบายหนึ่งที่เป็นไปได้จะเกี่ยวข้องกับสภาพการแข่งขัน หากคุณอ่านส่วนของ "ส่วน" คุณจะได้รับข้อมูลเสริม บางทีลินุกซ์ตีความสิ่งนี้ว่าหมายถึงส่วนที่เหลือของเซ็กเมนต์ไม่นับรวมถึงข้อมูลเสริมอีกต่อไป! ดังนั้นเมื่อได้รับกลุ่มใหม่จะถูกรวมเข้าด้วยกัน - ตามมาตรฐานหรือตามความแตกต่าง 1 ด้านบน

หากคุณต้องการเขียนโปรแกรมพกพาสูงสุดคุณควรหลีกเลี่ยงพื้นที่นี้โดยสิ้นเชิง เมื่อใช้ข้อมูลเสริมมันเป็นเรื่องธรรมดามากที่จะใช้ซ็อกเก็ตดาตาแกรม หากคุณต้องการทำงานบนแพลตฟอร์มที่แปลกประหลาดทั้งหมดที่ต้องการให้บางสิ่งบางอย่างเช่น POSIX ในทางเทคนิคคำถามของคุณน่าจะเป็นมุมที่มืดมนและยังไม่ผ่านการทดสอบ


คุณสามารถโต้แย้งว่า Linux ยังคงปฏิบัติตามหลักการสำคัญหลายประการ:

  1. "ได้รับข้อมูลเสริมราวกับว่าอยู่ในคิวพร้อมกับ octet ข้อมูลแรกในกลุ่ม"
  2. ข้อมูลเสริมจะไม่ "ตัดแบ่ง" ตามที่คุณใส่

อย่างไรก็ตามฉันไม่เชื่อว่าพฤติกรรม Linux มีประโยชน์อย่างยิ่งเมื่อคุณเปรียบเทียบกับพฤติกรรม BSD ดูเหมือนว่าโปรแกรมที่คุณอธิบายจะต้องเพิ่มวิธีแก้ปัญหาเฉพาะสำหรับ Linux และฉันก็ไม่รู้เหตุผลว่าทำไมลีนุกซ์คาดหวังให้คุณทำเช่นนั้น

มันอาจดูสมเหตุสมผลเมื่อเขียนโค้ดเคอร์เนล Linux แต่ไม่เคยผ่านการทดสอบหรือใช้งานโปรแกรมใด ๆ เลย

หรืออาจใช้รหัสโปรแกรมบางโปรแกรมซึ่งส่วนใหญ่ทำงานภายใต้ชุดย่อยนี้ แต่โดยหลักการแล้วอาจมี "บั๊ก" หรือเงื่อนไขการแข่งขัน

หากคุณไม่สามารถเข้าใจถึงพฤติกรรมของ Linux และการใช้งานตามวัตถุประสงค์ได้ฉันคิดว่านี่ถือว่าเป็น "มุมมืดและยังไม่ทดลอง" บน Linux


ขอบคุณสำหรับการตรวจสอบในเชิงลึก! ฉันคิดว่าของที่นี่คือฉันสามารถจัดการได้อย่างปลอดภัยด้วยบัฟเฟอร์สองตัว (แต่ละอันมีส่วนของข้อมูลและส่วนเสริม); หากฉันได้รับไฟล์อธิบายเมื่ออ่านครั้งแรกและพวกเขาไม่ได้เป็นของข้อความ แต่มีข้อความอื่นเริ่มขึ้นหากการอ่านครั้งถัดไปมีข้อมูลเสริมนั่นหมายความว่าฉันจะพบจุดสิ้นสุดข้อความข้อมูลของฉันเป็นเจ้าของเพย์โหลดแรก ในครั้งที่สองที่อ่าน สลับไปมาฉันควรจะสามารถจับคู่ข้อความกับเพย์โหลดตามตำแหน่งของไบต์แรกเสมอ
M Conrad
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.