ฉันสามารถละเว้นคำสั่งไบต์ในระบบเครือข่ายได้อย่างปลอดภัยหรือไม่?


24

ฉันกำลังพัฒนาแอปพลิเคชันไคลเอนต์เซิร์ฟเวอร์ที่ไคลเอนต์จะทำงานบน Windows และเซิร์ฟเวอร์อาจอยู่บน Linux บางทีฉันจะย้ายพอร์ตไคลเอ็นต์ไปยัง Mac และ Linux ในภายหลัง แต่ยังไม่เสร็จ

คอมพิวเตอร์ที่ใช้ในบ้านทุกวันนี้ใช้งานได้บนเครื่องเอนเดิ้ล ฉันไปสักพักหนึ่ง แต่ฉันไม่พบรายการอุปกรณ์ที่ทำงานบนเครื่องใหญ่ เท่าที่ฉันรู้ชิพ Motorola บางตัวยังคงใช้โทรศัพท์ขนาดใหญ่และอาจเป็นโทรศัพท์บางรุ่น (ฉันไม่ได้วางแผนที่จะย้ายแอพไปยังสมาร์ทโฟนดังนั้นจึงไม่สำคัญสำหรับฉัน) ดังนั้นทำไมฉันจึงจัดเรียงไบต์ของจำนวนเต็มทุกตัวทุกตัวย่อทุกตัวคูณคู่และอื่น ๆ สำหรับการอ่านและการเขียนเมื่อฉันรู้แล้วว่าทั้งเซิร์ฟเวอร์และไคลเอนต์ทำงานบนเอนเดเนี่ยนน้อย

นั่นเป็นเพียงงานที่ไม่จำเป็นที่ต้องทำ ดังนั้นคำถามของฉันคือ: ฉันสามารถเพิกเฉยต่อความปลอดภัยและส่งข้อมูลแบบ end-endian ได้อย่างปลอดภัยหรือไม่ อะไรคือข้อเสีย?


4
เครื่องจะทราบได้อย่างไรว่าพวกเขาได้รับข้อมูลเล็ก ๆ น้อย ๆ แทนที่จะเป็นข้อมูลขนาดใหญ่ปกติหรือมาตรฐาน?
Ixrec

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

2
@delnan ใช่พูดถึงเฉพาะส่วนของข้อมูลเท่านั้น แน่นอนฉันจะยังคงพูดคุยในเครือข่ายไบต์เพื่อเครือข่ายสแต็คตัวเอง
tkausl

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

1
@tkausl อีกสองความคิดที่ด้านข้าง: ตามกฎทั่วไปแล้ว IO นั้นช้ามากเมื่อเทียบกับการคำนวณดังนั้นค่าโสหุ้ยใด ๆ ที่แนะนำโดยการทำงานในระดับที่สูงกว่ามีความเป็นไปได้สูง อาจเกิดขึ้นได้ว่าห้องสมุดบางแห่งมีประสิทธิภาพสูงกว่าการใช้งานด้วยมือเนื่องจากการรวบรวมทรัพยากรที่ชาญฉลาดและการจัดการแบบอะซิงโครนัส ฯลฯ ดังนั้นฉันจะประเมินโซลูชันที่มีอยู่ก่อน นอกจากนี้จากคำอธิบายของคุณฉันจะใช้ความคิดเกี่ยวกับความสามารถในการปรับขนาดได้มากกว่าประสิทธิภาพซึ่งคุณอาจได้รับประโยชน์จากการใช้โปรโตคอลระดับสูงกว่าอีกครั้ง
godfatherofpolka

คำตอบ:


29

... เหตุใดฉันจึงต้องจัดเรียงไบต์อีกครั้ง ... เมื่อฉันรู้แล้วว่าทั้งเซิร์ฟเวอร์และไคลเอนต์ทำงานบน endian น้อย นั่นเป็นเพียงงานที่ไม่จำเป็นต้องทำ

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

มีการสั่งซื้อไบต์เครือข่ายมาตรฐาน มันเป็นเรื่องใหญ่ แต่ไม่มีอะไรบอกว่าคุณต้องปฏิบัติตามเมื่อออกแบบโปรโตคอลของคุณ หากคุณรู้ล่วงหน้าว่าส่วนใหญ่ของระบบที่ใช้รหัสของคุณจะเล็ก ๆ น้อย ๆ และประสิทธิภาพเป็นสิ่งสำคัญให้ประกาศว่า "สั่งซื้อไบต์มาตรฐาน tkausl" และไปกับมัน โดยปกติคุณจะเรียกhtons()ให้วางสิ่งต่าง ๆ ตามลำดับที่คุณต้องการเขียนมาโครที่เรียกhtots()ว่าคอมไพล์แบบมีเงื่อนไขเพื่อไม่มีอะไรในสถาปัตยกรรมแบบ endian เล็ก ๆ น้อย ๆ และทำการจัดเรียงบน big-endian อีกครั้ง

การบำรุงรักษาโค้ดให้ทำทั้งการแปลงขาเข้าและขาออกนั้นไม่ใช่เรื่องใหญ่ หากคุณมีข้อความจำนวนมากหาวิธีในการแสดงและเขียนโปรแกรมเพื่อสร้างการแปลงขาเข้าและขาออก


10
การใช้ถ้อยคำwhen designing your protocolมีความสำคัญเนื่องจากมันบอกเป็นนัยว่าตัวเลือกนี้มีอยู่เฉพาะเมื่อออกแบบโปรโตคอลใหม่และไม่ใช่เมื่อใช้บางโปรโตคอลที่มีอยู่ และการกล่าวถึงความต้องการhtots(และครอบครัวทั้งหมดของฟังก์ชั่น) ทำให้ชัดเจนว่าการเลือกลำดับไบต์ที่แตกต่างไม่ใช่สิ่งที่เราทำเพื่อให้โค้ดง่ายขึ้น แต่มันอาจทำให้เร็วขึ้นเล็กน้อย
kasperd

4
มี (ที่ไม่ได้มาตรฐาน แต่ที่พบบ่อยมากวันนี้) ฟังก์ชั่นhtole32(), htole16(), le16toh()ฯลฯ ฟังก์ชั่นใช้ได้เช่นกัน ไฟล์ที่จะรวมเพื่อรับการประกาศเหล่านี้น่าเสียดายที่เป็นมาตรฐานที่น้อยกว่า: <endian.h>หรือ<sys/types.h>ขึ้นอยู่กับแพลตฟอร์ม
torek

คำตอบนี้ใช้ได้ แต่ฉันคิดว่าการสันนิษฐานว่าการแสดงอาจมีความสำคัญในกรณีที่กำหนดน่าจะเป็นข้อสันนิษฐานที่ผิดส่วนใหญ่ขึ้นอยู่กับความเชื่อโชคลางมากกว่าข้อเท็จจริง
Doc Brown

1
@DocBrown: ฉันมักจะชี้ให้เห็นว่าโปรโตคอล X ได้รับการสนับสนุนการเลือกคำสั่งไบต์ของคุณเองเป็นเวลา 30 ปีและเป็นทรัพยากรที่แน่นกลับมาแล้วไม่มีใครเคยบ่นว่ามันเป็นปัญหา
Blrfl

7

มันเป็นโปรโตคอลของคุณ

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

นี่หมายถึงค่าใช้จ่าย ตอนนี้คุณต้องทำเครื่องหมาย endianness ของคุณอย่างใด ทำอย่างนั้นและฉันสามารถอ่านอะไรก็ได้

หากคุณไม่ต้องการให้ข้อมูลค่าใช้จ่ายและ CPU ของคุณจะเบื่อและมองหาสิ่งที่จะทำแล้วเป็นไปตาม


6

ดังนั้นคำถามของฉันคือ: ฉันสามารถเพิกเฉยต่อ endianess ได้อย่างปลอดภัยและเพียงแค่ส่งข้อมูล endian เล็ก ๆ น้อย ๆ ?

มีการตีความสองอย่าง:

  • หากคุณออกแบบแอปพลิเคชัน / โปรโตคอลของคุณให้เป็น1 ให้ส่งผู้ใช้ปลายทางรายย่อยเสมอคุณจะไม่เพิกเฉยต่อความรัก

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

    นั่นคือ "ปลอดภัย" 2หรือไม่? นั่นสำหรับคุณที่จะตัดสิน! แต่แน่นอนว่ามีแพลตฟอร์มฮาร์ดแวร์ทั่วไปที่ใช้น้อย - endian, big-endian หรือ ... bi-endian

    อ้างอิง:

อะไรคือข้อเสีย?

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

เห็นได้ชัดว่าแพลตฟอร์มรุ่นปัจจุบันส่วนใหญ่นั้นเป็นแบบเอนเดียนเล็ก ๆ น้อย ๆ แต่ 1) บางตัวไม่ใช่และ 2) เราสามารถเดาได้ว่าจะเกิดอะไรขึ้นในอนาคต


1 - เสมอ ... รวมถึงบนแพลตฟอร์มที่ค่อนข้างใหญ่

2 - "ปลอดภัย" หมายถึงอะไร? หากคุณกำลังขอให้เราทำนายทิศทางในอนาคตของแพลตฟอร์มฮาร์ดแวร์ ... ฉันเกรงว่าจะไม่สามารถตอบคำถามได้อย่างเป็นกลาง


3

Endianness ไม่ได้เป็นเพียงการพิจารณาเท่านั้น มีขนาดเป็นจำนวนเต็มมีการจัดเรียงโครงสร้างที่คุณอาจต้องการส่งหรือรับเป็นต้น

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

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


3

BSD เครือข่ายสแต็กมาตรฐานใน C มีhton/ ntohฟังก์ชันการทำงาน ( network-to-host/ host-to-network) ซึ่งขยายเป็น no-ops บนเครื่องเครือข่ายดั้งเดิม (endian ใหญ่) คุณต้องการคู่หูของคุณเองสำหรับสถานการณ์จำลองที่คำสั่งไบต์แบบเนทีฟเครือข่ายนั้น endian น้อย

นั่นเป็นวิธีที่แข็งแกร่งในการทำ

มันจะแปลกใหม่ แต่ฉันไม่เห็นอะไรผิดปกติ คอมพิวเตอร์ในเครือข่ายจะได้รับ bytestreams เสมอและพวกเขาจำเป็นต้องเห็นด้วยกับโปรโตคอลในการตีความไบต์เหล่านั้น นี่เป็นเพียงส่วนหนึ่งของมัน


3

โปรโตคอลต่าง ๆ ที่ใช้ในการส่งข้อมูลระหว่างเซิร์ฟเวอร์ใช้หมายเลข endian น้อย:

  1. BSON
  2. โปรโตคอลบัฟเฟอร์
  3. Capn Proto

ดูhttps://en.wikipedia.org/wiki/Comparison_of_data_serialization_formatsเพื่อดูรายละเอียดเกี่ยวกับรูปแบบต่างๆซึ่งบางส่วนมีหมายเลขเล็ก ๆ น้อย ๆ และบางส่วนมีหมายเลขใหญ่

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

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


2

ตัวอย่างหนึ่งของระบบ endian ขนาดใหญ่คือ MIPS ที่ใช้ในเราเตอร์ ทั้ง ARM และ MIPS สามารถสลับ endian ได้ แต่บ่อยครั้งที่ MIPS นั้นเป็น endian ใหญ่เพราะทำให้ฮาร์ดแวร์เครือข่ายง่ายขึ้น (ส่วนที่สำคัญที่สุดของคำคือส่วนที่คุณได้รับก่อนและสามารถตัดสินใจกำหนดเส้นทางก่อนที่คุณจะได้รับส่วนที่เหลือของ คำแทนที่จะต้องบัฟเฟอร์ทั้งคำ)

ดังนั้นขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย 'Linux' แต่ถ้าคุณต้องการเรียกใช้แอปเซิร์ฟเวอร์ของคุณในระบบที่เล็กกว่าเช่นเราเตอร์ที่ใช้ OpenWRT คุณอาจต้องพิจารณาการสนับสนุนจาก endian

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


0

ฉันไม่คิดว่าคำตอบใด ๆ นั้นค่อนข้างแม่นยำเพียงพอ ตามวิกิพีเดีย endianness คือคำสั่งของไบต์ประกอบด้วยคำ

ให้ใช้ 4 ไบต์และตีความว่าเป็น int หนึ่งระบบ endian เล็กน้อยไบต์จะถูกตีความจากขวาไปซ้ายและรอง verca ในระบบ endian ขนาดใหญ่ เห็นได้ชัดว่ามันเป็นสิ่งสำคัญที่จะต้องเห็นด้วยกับที่สิ้นสุดในการตีความ int

ให้ซูมออกเล็กน้อยไปยังโปรโตคอลเครือข่ายที่ทันสมัยซึ่งอาจใช้ json หรือ xml ไม่มีรูปแบบเหล่านั้นที่จะถ่ายโอน int เป็น 4 ไบต์ พวกเขาจะถ่ายโอนข้อมูลเป็นข้อความซึ่งจะถูกแยกวิเคราะห์เป็น int ในด้านที่ได้รับ

ดังนั้นในที่สุด endianness ไม่สำคัญเมื่อใช้ json หรือ xml เรายังต้องใช้ endian ใหญ่สำหรับ tcp headers ซึ่งเป็นเหตุผลที่เรียกว่า network byte order แต่โปรแกรมเมอร์ส่วนใหญ่ไม่จำเป็นต้องยุ่งกับสิ่งเหล่านี้ในชีวิตประจำวัน

ใช้กันอย่างแพร่หลายเข้ารหัสส่วนใหญ่ในวันนี้คือ UTF-8 ซึ่ง happpens ยังเป็นภูมิคุ้มกันในการแก้ไขปัญหาเกี่ยวกับการ endianness

ดังนั้นฉันจะบอกว่าใช่ มีความปลอดภัยที่จะไม่สนใจ endianness เมื่อใช้รูปแบบข้อความที่ถ่ายโอนโดยใช้ utf-8


สองคะแนนโหวตลงและไม่มีความคิดเห็น ยิ่งใหญ่
Esben Skov Pedersen

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

2
ฉัน upvoting นี้เพราะมันสัมผัสความจริงที่ว่ารูปแบบของน้ำหนักบรรทุกไม่มีส่วนเกี่ยวข้องกับโปรโตคอลพื้นฐาน บางคนชอบที่จะขุดหาปัญหาที่เกิดขึ้น
Zdenek

0

ดูเหมือนว่าระบบ endian ขนาดใหญ่กำลังจะออกไป ยูนิกซ์แบบดั้งเดิมจำนวนมากใช้ endian ใหญ่ แต่พวกมันก็ลดลงมานานหลายปีเพื่อสนับสนุน linux ใน x86

แขนเป็น bi-endian แต่ตัวแปร endian ใหญ่ดูเหมือนจะไม่ค่อยเห็น

mips มีอยู่ในทั้งสองรุ่น Afaict ตัวแปร endian ใหญ่ส่วนใหญ่จะเห็นได้ในเครือข่ายการสมัคร (ด้วยเหตุผลทางประวัติศาสตร์โปรโตคอลอินเทอร์เน็ตโดยทั่วไปใช้ Endian ใหญ่)

ppc นั้นเป็น endian ขนาดใหญ่ที่มีบางส่วนรองรับทั้ง endians แต่ IBM ดูเหมือนว่าจะผลักดันโหมด endian สำหรับ ppc แบบ 64 บิต (ตอนนี้พวกเขาดันพอร์ต ppc64el ลงใน Debian และ Ubuntu)

Sparc โดยปกติแล้วจะเป็น endian ที่มีขนาดใหญ่ แต่ดูเหมือนว่าจะลดลงอีกครั้ง

หากคุณกำลังใช้โปรโตคอลที่มีอยู่แล้วแน่นอนคุณต้องปฏิบัติตามข้อกำหนดของมัน ถ้าคุณต้องการให้ IETF เป็นพรแก่โปรโตคอลใหม่ของคุณแล้ว endian ใหญ่น่าจะง่ายกว่าเพราะนั่นคือสิ่งที่พวกเขาใช้อยู่แล้วในโปรโตคอลที่มีอยู่แล้ว แต่ IMO สำหรับการออกแบบ protocold "greenfield" แบบใหม่ที่เป็นไปได้น้อย endian

คุณสามารถใส่มาโครได้ตั้งแต่เริ่มต้นซึ่งจะไม่มีตัวเลือกในระบบ endian เล็ก ๆ น้อย ๆ หรือคุณไม่สามารถรำคาญจนกระทั่ง / จนกว่าคุณจะต้องพอร์ตไปยังระบบ endian ขนาดใหญ่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.