Bisakah saya dengan aman mengabaikan pesanan byte dalam jaringan?

24

Saya sedang mengembangkan aplikasi server-client di mana klien akan berjalan di Windows dan server mungkin di Linux. Mungkin nanti saya akan mengirim klien ke Mac dan Linux, tetapi belum.

Semua komputer rumahan saat ini dijalankan oleh little-endian. Saya googled beberapa saat, tetapi saya tidak dapat menemukan daftar perangkat yang berjalan pada big-endian. Sejauh yang saya tahu, beberapa chip Motorola masih menggunakan big-endian dan mungkin beberapa ponsel (saya tidak berencana porting aplikasi ke smartphone, jadi ini tidak masalah bagi saya). Jadi, mengapa saya mengatur ulang byte dari setiap integer, setiap short, float, double, dan seterusnya, untuk membaca dan menulis , ketika saya sudah tahu bahwa keduanya, server dan klien dijalankan pada little-endian?

Itu hanya pekerjaan yang tidak perlu dilakukan. Jadi, pertanyaan saya adalah: Dapatkah saya dengan aman mengabaikan endianness dan hanya mengirim data little-endian? Apa kerugiannya?

tkausl
sumber
4
Bagaimana mesin akan tahu jika mereka menerima data little-endian alih-alih data big-endian biasa / standar?
Ixrec
2
Anda perlu membedakan antara metadata yang diperlukan oleh protokol jaringan, dan payload yang hanya sekelompok byte yang tidak diinterpretasikan untuk semua orang kecuali kode Anda. Saya harap Anda tidak menggulung tumpukan jaringan Anda sendiri. Alhasil saya menganggap pertanyaannya hanya soal payload, benar?
2
@nannan ya, hanya berbicara tentang payload. Tentu saja saya masih akan berbicara dalam network-byte-order ke network-stack itu sendiri.
tkausl
3
Hanya pemikiran di samping: Apakah benar-benar perlu bagi Anda untuk bekerja pada tingkat abstraksi di mana endianness menjadi perhatian? Mungkin bermanfaat untuk mempertimbangkan menggunakan protokol yang ada perpustakaan yang sesuai yang merangkum semua "kekacauan" tingkat rendah ini. Kemudian, Anda juga memiliki bonus tambahan yang menambahkan klien lebih lanjut dapat dilakukan lebih mudah.
godfatherofpolka
1
@tkausl Hanya dua pemikiran lagi di samping: Sebagai aturan umum, IO sangat lambat dibandingkan dengan perhitungan, sehingga setiap overhead yang diperkenalkan dengan bekerja pada level abstraksi yang lebih tinggi kemungkinan besar dapat diabaikan. Bahkan mungkin terjadi bahwa beberapa perpustakaan mengungguli implementasi handrolled karena pengumpulan sumber daya yang pintar dan penanganan asinkron, dll. Jadi, pertama-tama saya akan dengan hati-hati mengevaluasi solusi yang ada. Selain itu, mengingat uraian Anda, saya juga akan menghabiskan beberapa pemikiran tentang skalabilitas daripada kinerja, di sini Anda mungkin lagi mendapat manfaat dari menggunakan protokol tingkat yang lebih tinggi.
godfatherofpolka

Jawaban:

29

... mengapa saya mengatur ulang byte ... ketika saya sudah tahu bahwa keduanya, server dan klien berjalan pada endian kecil? Itu hanya pekerjaan yang tidak perlu dilakukan.

Ini hanya tidak perlu jika Anda dapat menjamin kode Anda akan selalu berjalan pada arsitektur little-endian. Jika Anda berniat untuk memiliki umur yang panjang, ada baiknya upaya ekstra untuk menghindari mengganggu kode terbukti dengan baik satu dekade dari sekarang ketika beberapa arsitektur big-endian telah menjadi "dalam" hal dan Anda menemukan itu menjadi pasar yang baik untuk aplikasi Anda.

Ada pemesanan byte standar jaringan. Ini big-endian, tetapi tidak ada yang mengatakan Anda harus mematuhinya ketika merancang protokol Anda. Jika Anda tahu sebelumnya, sebagian besar sistem yang menjalankan kode Anda adalah little-endian dan kinerjanya sangat penting, nyatakan bahwa "tkausl byte standar dipesan" dan ikuti saja. Di mana Anda biasanya akan menelepon htons()untuk meletakkan hal-hal dalam urutan yang Anda butuhkan, menulis makro yang disebut htots()kondisional mengkompilasi apa-apa pada arsitektur little-endian dan melakukan pengaturan ulang pada big-endian.

Mempertahankan kode untuk melakukan konversi masuk dan keluar bukanlah upaya yang besar. Jika Anda memiliki jumlah pesan yang sangat besar, temukan cara untuk mengekspresikannya dan tulis sebuah program untuk menghasilkan konversi masuk dan keluar.

Blrfl
sumber
10
Kata-kata when designing your protocolitu penting, karena kata itu secara implisit mengatakan bahwa opsi ini hanya ada ketika merancang protokol baru dan tidak ketika mengimplementasikan beberapa protokol yang ada. Dan menyebutkan kebutuhan untuk htots(dan benar-benar seluruh keluarga fungsi), juga menjelaskan bahwa memilih pemesanan byte yang berbeda bukanlah sesuatu yang dilakukan seseorang untuk membuat kode lebih sederhana, tetapi mungkin membuatnya sedikit lebih cepat.
kasperd
4
Ada (non-standar tapi sangat umum hari ini) fungsi htole32(), htole16(), le16toh(), dll, fungsi yang tersedia juga. Sayangnya, file yang akan disertakan untuk mendapatkan deklarasi ini kurang standar: <endian.h>atau <sys/types.h>tergantung pada platform.
torek
Jawaban ini baik-baik saja, tetapi saya pikir asumsi bahwa kinerjanya mungkin kritis karena kasus yang diberikan kemungkinan besar adalah asumsi yang salah, lebih didasarkan pada takhyul daripada fakta.
Doc Brown
1
@DocBrown: Saya selalu ingin menunjukkan bahwa protokol X telah mendukung memilih urutan byte Anda sendiri selama 30 tahun, dan sekencang sumber daya saat itu, tidak ada yang pernah mengeluh bahwa itu adalah masalah.
Blrfl
7

Ini protokol Anda.

Anda tidak dapat mengabaikannya dengan aman. Tetapi Anda dapat dengan aman memberi label. Anda mengontrol klien dan server. Anda mengontrol protokol. Bukankah masuk akal untuk tidak peduli apakah itu big-endian atau little-endian selama Anda tahu apakah kedua belah pihak setuju?

Ini berarti overhead. Sekarang Anda harus menandai endianness Anda, entah bagaimana. Lakukan itu, dan saya bisa membacanya pada apa saja.

Jika Anda tidak ingin data overhead, dan CPU Anda bosan dan mencari sesuatu untuk dilakukan, maka sesuaikan .

candied_orange
sumber
6

Jadi, pertanyaan saya adalah: Dapatkah saya dengan aman mengabaikan endianess dan hanya mengirim data little-endian?

Ada dua interpretasi tentang itu:

  • Jika Anda mendesain aplikasi / protokol Anda untuk selalu 1 mengirim little-endian, maka Anda TIDAK mengabaikan endianess.

  • Jika Anda merancang aplikasi / protokol Anda untuk mengirim / menerima apa pun endianess asli, maka mereka akan berfungsi selama Anda menjalankan aplikasi Anda pada platform dengan endianess asli yang sama.

    Apakah itu "aman" 2 ? Itu bagi Anda untuk menilai! Tetapi tentu saja ada platform perangkat keras umum yang menggunakan little-endian, big-endian atau ... bi-endian.

    Referensi:

Apa kerugiannya?

Kerugian yang jelas dari mengabaikan endianess adalah bahwa jika Anda / pengguna Anda perlu menjalankan aplikasi / protokol antara platform dengan endianess asli yang berbeda, maka Anda memiliki masalah. Aplikasi akan rusak, dan Anda harus mengubahnya untuk memperbaiki masalah. Dan menangani masalah kompatibilitas versi, dan sebagainya.

Jelas, sebagian besar platform generasi saat ini aslinya sedikit-endian, tetapi 1) beberapa tidak, dan 2) kita hanya bisa menebak apa yang akan terjadi di masa depan.


1 - Selalu ... termasuk pada platform yang asli-endian.

2 - Memang, apa artinya "aman"? Jika Anda meminta kami untuk memprediksi arah masa depan platform perangkat keras ... Saya khawatir itu tidak dapat dijawab secara objektif.

Stephen C
sumber
3

Endianness bukan satu-satunya pertimbangan. Ada ukuran bilangan bulat, ada kemasan struct yang mungkin ingin Anda kirim atau terima, dan sebagainya.

Anda dapat mengabaikan semua ini. Tidak ada yang bisa memaksamu. Di sisi lain, cara yang aman dan dapat diandalkan adalah mendokumentasikan format eksternal, dan kemudian menulis kode yang akan membaca atau menulis format eksternal dengan benar, tidak peduli apa prosesor Anda, bahasa pemrograman Anda, dan implementasi bahasa pemrograman Anda.

Biasanya tidak banyak kode. Tetapi ini memiliki manfaat besar: Orang yang membaca kode Anda tidak akan curiga bahwa Anda tidak tahu apa-apa, tidak tahu apa-apa tentang menukar data eksternal, dan menulis kode yang umumnya tidak dapat dipercaya.

gnasher729
sumber
3

Tumpukan jaringan BSD standar dalam C memiliki fungsi hton/ ntoh( network-to-host/ host-to-network) yang meluas ke no-ops pada mesin asli jaringan (big endian). Anda akan membutuhkan rekan-rekan Anda sendiri untuk ini untuk skenario di mana urutan byte asli-jaringan sedikit endian.

Itu cara yang kuat untuk melakukannya.

Itu tidak konvensional, tetapi saya tidak melihat ada yang salah dengan itu. Komputer jaringan selalu mendapatkan bytestreams dan mereka harus menyetujui protokol tentang bagaimana menafsirkan byte tersebut. Ini hanya sebagian saja.

PSkocik
sumber
3

Berbagai protokol yang digunakan untuk mengirimkan data antar server menggunakan nomor endian kecil:

  1. BSON
  2. Buffer Protokol
  3. Capn Proto

Lihat https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats , untuk perincian tentang berbagai format yang beberapa di antaranya memiliki angka little-endian, dan beberapa memiliki angka big-endian.

Sama sekali tidak ada yang salah dengan menggunakan protokol berdasarkan nomor endian kecil. Mesin endian besar sama mampu membaca angka endian kecil seperti mesin endian kecil dapat membaca angka endian besar. Banyak orang telah melakukannya secara khusus untuk menghindari biaya perhitungan tambahan dari decoding angka big-endian pada mesin endian kecil.

Jika Anda membangun protokol Anda di atas salah satu protokol yang ada, maka Anda bahkan tidak perlu khawatir tentang masalah ini, itu sudah diurus. Ketika Anda memutuskan untuk menjalankan kode Anda pada platform big-endian, maka pustaka yang mengimplementasikan protokol ini akan secara otomatis memastikan bahwa Anda mendekode nilai-nilai dengan benar.

Winston Ewert
sumber
2

Salah satu contoh sistem big endian adalah MIPS yang digunakan dalam router. Baik ARM dan MIPS adalah endian-switchable, tetapi seringkali MIPS adalah big endian karena membuat perangkat keras jaringan lebih mudah (bagian terpenting dari sebuah kata adalah bagian yang Anda terima pertama dan dapat membuat keputusan routing sebelum Anda menerima sisa dari kata, daripada harus buffer seluruh kata).

Jadi itu tergantung apa yang Anda maksud dengan 'Linux', tetapi jika Anda ingin menjalankan aplikasi server Anda pada sistem yang lebih kecil seperti router yang menjalankan OpenWRT maka Anda mungkin harus mempertimbangkan dukungan big endian.

Seperti biasa, membuat asumsi yang disederhanakan adalah optimasi yang sangat masuk akal sampai Anda menemukan sesuatu yang tidak sesuai dengan asumsi. Hanya Anda yang bisa mengatakan betapa menyakitkannya melepaskan mereka jika Anda menemukan masalah seperti itu.

pengguna1908704
sumber
0

Saya tidak berpikir ada satu jawaban pun yang cukup tepat. Menurut Wikipedia endianness adalah urutan byte yang terdiri dari sebuah kata.

Mari kita ambil 4 byte dan menafsirkannya sebagai int. Satu sistem endian kecil byte akan ditafsirkan dari kanan ke kiri, dan sebaliknya pada sistem big endian. Jelas penting untuk menyetujui tujuan mana yang menafsirkan int.

Mari tampilannya sedikit keluar ke protokol jaringan modern yang bisa menggunakan json atau xml. Tak satu pun dari format itu akan mentransfer int sebagai 4 byte. Mereka akan mentransfer data sebagai teks yang akan diurai sebagai int di sisi penerima.

Jadi pada akhirnya endianness tidak masalah saat menggunakan json atau xml. Kita masih perlu menggunakan big endian untuk tcp header yang oleh karena itu disebut urutan byte jaringan, tetapi kebanyakan programmer tidak perlu mengacaukannya setiap hari.

Pengkodean yang paling banyak digunakan saat ini adalah utf-8 yang juga kebal terhadap masalah terkait endianness .

Jadi saya akan mengatakan ya. Aman untuk mengabaikan endianness ketika menggunakan format berbasis teks yang ditransfer menggunakan utf-8.

Esben Skov Pedersen
sumber
dua suara turun dan tidak ada komentar. Besar.
Esben Skov Pedersen
1
Saya bukan downvoter tetapi jawaban ini tampaknya mengabaikan / menolak pertanyaan yang benar-benar valid. Hanya karena beberapa protokol berbasis teks tidak berarti semua protokol seharusnya.
Peter Green
2
Saya meng-upgrade ini karena menyentuh fakta bahwa format payload tidak ada hubungannya dengan protokol yang mendasarinya. Beberapa orang suka menggali masalah buatan.
Zdenek
0

Sistem big endian tampaknya sedang keluar. Banyak unix tradisional menggunakan big endian tetapi telah mengalami penurunan selama bertahun-tahun untuk linux pada x86.

lengan adalah bi-endian tetapi varian big endian tampaknya jarang terlihat.

mips ada di kedua varian. Varian big endian sebagian besar terlihat pada applicances jaringan (karena alasan historis protokol internet umumnya menggunakan big endian).

ppc adalah endian besar secara tradisional dengan beberapa bagian mendukung kedua endian tetapi IBM tampaknya sekarang mendorong sedikit mode endian untuk ppc 64-bit (mereka baru-baru ini mendorong port ppc64el ke Debian dan Ubuntu).

SPARC biasanya big endian tetapi sekali lagi tampaknya sedang menurun.

Jika Anda menerapkan protokol yang ada maka jelas Anda harus mengikuti spesifikasinya. Jika Anda ingin IETF memberkati protokol baru Anda maka big endian kemungkinan akan lebih mudah karena itulah yang sudah mereka gunakan dalam protokol mereka yang ada tetapi IMO untuk desain protocold "greenfield" baru little endian adalah jalan yang harus ditempuh.

Anda dapat memasukkan makro dari awal yang tidak akan ada pada sistem endian kecil atau Anda tidak dapat mengganggu sampai / kecuali Anda perlu port ke sistem endian besar.

Peter Green
sumber