Qanday qilib portativ tarmoq orqali tarmoq tuzilishi mumkin?

Menda quyidagicha ta'riflangan C tuzi mavjud:

typedef struct servData {
    char max_word[MAX_WORD];
    char min_word[MAX_WORD];
    int word_count ;
} servSendData ;

"MAX_WORD" har qanday qiymat bo'lishi mumkin. Hozirda ushbu tuzilmaning bir misoli bo'lsa:

servSendData  myData ;

Va agar men bu misolni to'ldirib, keyin uni tarmoq orqali yuboradigan bo'lsam, mening serverimni hamda mijozni 64 bitli tizimda yoki 32 bitli tizimda ishlashni istaganimni hisobga oladigan har qanday ko'chma muammolar bo'ladi.

Men ma'lumotlarni quyidagicha yuboraman:

//server side
strcpy(myData.max_word, "some large word") ;
strcpy(myData.min_word, "small") ;
myData.word_count=100 ;
send(sockFd, (char*)&myData, sizeof(myData);

//client side
recv(sockFd, (char*)&myData, sizeof(myData);
printf("large word is %s\n", myData.max_word) ;
printf("small word is %s\n", myData.min_word) ;
printf("total words is %d\n", myData.word_count) ;
6
TLV (turdagi, uzunlik, qiymat) kodlash va "ketma-ketlashtirish" va XDR (tashqi ma'lumotlar namoyish) ni tadqiq qilishingiz kerak.
qo'shib qo'ydi muallif Jonathan Leffler, manba
qo'shib qo'ydi muallif Mints97, manba

5 javoblar

Ha, albatta taşınabilirlik muammosi bo'ladi.

Qurilish a'zolarining hizalanishi bir xil platformada turli xil kompilyatorlar orasida ham farq qilishi mumkin, faqatgina turli platformalar haqida gap ketadi. Buning hammasi, sizeof (int) ning barchasi bo'yicha bir xilligini taxmin qilmoqda (garchi odatda, odatda --- bo'lsa-da), lekin odatda " "va eng yaxshi umid?).

Bu ikkala kompyuterda ham MAX_WORD bir xil bo'lsa ham, ushlab turadi (ular bu yerdan chiqadi deb o'ylayman, agar ular bo'lmasa, unda siz bu erda muammodasiz).

Nima qilishingiz kerak bo'lsa, har bir sohani alohida-alohida yuboring (va qabul qiling). Bundan tashqari, sizeof (int) va endianness bilan bog'liq muammo ham mavjud, shuning uchun sistemadan tarmoq baytiga (aylantiruvchi funktsiya) aylantirish uchun htonl() ntohl() ). Ular har ikkisi ham qattiq, ma'lum bo'lgan hajmga ega bo'lgan uint32_t kodini qaytaradi.

send(sockFd, myData.max_word, sizeof(myData.max_word));//or just MAX_WORD
send(sockFd, myData.min_word, sizeof(myData.min_word));
uint32_t count = htonl(myData.word_count);//convert to network byte order
send(sockFd, &count, sizeof(count));

// error handling!
if((ret = recv(sockFd, myData.max_word, sizeof(myData.max_word))) != sizeof(myData.max_word))
{
   //handle error or read more data
}
...//and so on
// remember to convert back from network byte order on recv!
// also keep in mind the third field is now `uint32_t`, and not `int` in the stream
5
qo'shib qo'ydi
@black: Yaxshi fikr, lekin men faqat umumiy fikrni olishga harakat qilardim. Men uni biroz tuzataman.
qo'shib qo'ydi muallif Tim Čas, manba
Eslatma: if sharti noto'g'ri. Hatto bu to'g'ri bo'lsa ham, u xato bo'lmaydi. Xato -1 bilan ko'rsatiladi.
qo'shib qo'ydi muallif edmz, manba

Boshqa relyeflar shuni ta'kidladilarki, turli xil kompilyatorlar/so'z hajmi va endian strukturasi bo'lgan turli xil mashinalar orasida C strukturasini nusxalashda haqiqiy muammolar mavjud. Ushbu muammoni hal etishning eng keng tarqalgan usuli - ma'lumotlaringizni mashinaga mustaqil formatga aylantirish, uni tarmoq orqali uzatish va keyin uni qabul qiluvchining strukturasiga o'tkazish. Bu shunday qilish uchun juda ko'p texnologiyalarning mavjudligi shunga o'xshash umumiy talabdir. Buning uchun avvalambor mening fikrimga baho beradigan ikkita narsa gsoap va rpcgen bo'lsa-da, ehtimol ko'plab boshqa variantlar mavjud.

Men asosan gsoapdan foydalandim va dastlabki o'rganish kursisidan o'tib ketganingizdan so'ng siz yaxshi (bir nechta mavzular bilan) shaffof echimlarni ishlab chiqa olasiz va siz uchun ham tarmoq va ma'lumotlar tarjimalarini o'zida mujassam etadi.

Ushbu marshrutni pastga tushirmoqchi bo'lmasangiz, unda eng xavfsiz yondashuv ma'lumotlarini standart mag'lubiyatga formatga aylantiradigan marshrutlarni yozishdir (agar Unicode bilan muammo bo'lsa, bu hisobni ham inobatga oling) va keyin tarmoq orqali yuboring.

1
qo'shib qo'ydi
Ha @ jackson siz recv() funktsiyasi bilan bog'liq. Haqiqiy kodda men shaxsiy maydonlarni o'qishni boshlamasdan oldin barcha ma'lumotlarning qabul qilinishini ta'minlayman.
qo'shib qo'ydi muallif user3282758, manba

Endians haqida qayg'urishingiz kerak.

Hton() yoki ntoh() funktsiyalarini kichik va katta endianlar orasida aylantirish uchun foydalaning.

1
qo'shib qo'ydi
@ Timxas Qanday qilib o'zingizning haqiqiy kichkina javobingiz bilan "qat'iyan rozi bo'lasiz"? Endiannessga qaraganda ko'proq ko'chma masalalar mavjud va sizning javobingiz ularni to'liq o'z ichiga oladi, ammo bu javobning hammasi to'g'ridir.
qo'shib qo'ydi muallif 5gon12eder, manba
Bu erda men o'zimning muammolarning eng kami endianness. Bu muammo, lekin bu erda sizeof (int) va strukturani to'ldirish (bu erda int ning turli hizalanishi tufayli) bu erda katta muammolar.
qo'shib qo'ydi muallif Tim Čas, manba
@Lui: X86 va boshqalar x64 da ( long ) odatda odatda emas. Lekin, bu derleyiciga bog'liq bo'lishi mumkin. Bu quyidagilardan iborat: viva64.com/en/t/0012 - bir sistema ILP64 (64-bit int ), boshqa LLP64 (32-bit int ) va boshqa (o'ylab ko'milgan) I16LP32 (16- bit int ).
qo'shib qo'ydi muallif Tim Čas, manba
@ 5gon12eder: U eng kam muammosiga ega bo'lgan masalaga e'tibor qaratadi va boshqa barcha narsalarni e'tiborsiz qoldiradi.
qo'shib qo'ydi muallif Tim Čas, manba
@Lui: 16-bitli int : IP16L32 yoki IP16L32LL64 (64-bit uzunligi ) odatda 8-bit (va ehtimol 16-bitli) mikrokontroller uchun ishlatiladi. Ulardan ba'zilari tarmoq qobiliyatiga ega (yoki qurilgan yoki qo'shimcha qurilmalar yordamida, Arduino w/Ethernet qalqoni deb hisoblang).
qo'shib qo'ydi muallif Tim Čas, manba
OK, ha, tushunaman, x86 da int bir x64 protsessida intdan kichikroq. Int ning o'rniga uint32_t kabi turlari yoki shunga o'xshash narsalarni ishlatishi kerak.
qo'shib qo'ydi muallif Lui, manba

Agar siz ko'milgan dasturiy ta'minotni yozmasangiz, dasturlarni ketma-ket serializmasdan ma'lumotlar yuborish juda kamdan-kam hollarda yaxshi.

Xuddi shu narsa juda qulay bo'lmagan va "g'ildirakni qayta kashf qilish" kabi bir oz his qiladigan xom naychalarni ishlatish uchun ham xuddi shunday.

Ko'plab kutubxonalar sizga yordam berishi mumkin! Albatta, ularni ishlatishingiz shart emas, lekin ularning hujjatlarini o'qish va ularning qanday ishlashini yaxshiroq tanlov qilishga yordam beradi. Siz hali rejalashtirmagan narsalar qutidan chiqishi mumkin (masalan, tizimingizni yangilash va xabar formati o'zgarganda nima sodir bo'ladi?)

Ketma-ket joylashtirish uchun ushbu umumiy maqsadlardagi formatlarni o'qing:

  • Inson o'qilishi: JSON, XML, YAML, boshqalar ...
  • Ikkilik: Protobuf , TPL , evro , BSON, MessagePack va boshqalar.

Socket abstraction uchun, yuqoriga qarash

  • ASIO ni oshiring
  • ZeroMQ
  • nanomsg
  • Boshqa ko'plar
0
qo'shib qo'ydi

Siz tuzilish paketini dan foydalanishingiz mumkin. Ko'pgina C derleyicileriyle, ma'lum bir tuzilish hizalamasını mumkin. Ba'zan siz kerak bo'lgan narsalar uchun - struct ni tarmoq orqali uzatish uchun ishlatiladi.

Shuni yodda tutingki, bu hali endianness masalalarini qoldiradi, shuning uchun bu universal echim emas.

0
qo'shib qo'ydi
Bundan tashqari standart/portativ emas C (yoki C + POSIX, chunki biz rozetkalarni gaplashyapmiz), shuningdek, sizeof (int) bilan bog'liq muammolar qolmoqda. Paketdan foydalanish, odatda dasturni nolga teng bo'lmagan o'qishlar bilan kodlaydi (hech bo'lmaganda x86-da emas, chunki boshqa arxitekturalarning aksariyati nolga teng bo'lmagan o'qishlarni o'qimaydi/yozmaydi), x 86 da bu kabi o'qishlarni sekinroq qiladi).
qo'shib qo'ydi muallif Tim Čas, manba
Yaxshi, texnik jihatdan u bir necha 64- yoki 32-bit tizimni aytdi, lekin ha, ehtimol 16-bit int s bilan yo'q. Bunga javob , keyinchalik uzun yoki shunga o'xshash tuzilishga qo'shilishga qaror qilishi mumkin va bu muammoni uradi; Men bu masalani umumiy tarzda hal qilishga harakat qilardim.
qo'shib qo'ydi muallif Tim Čas, manba
@ Timxas: yaxshi, men bu yo'lni tanlashning bir usuli, deb aytmayapman, shundagina ba'zi muvofiqlik masalalaridan shu tarzda qochish mumkin. Bundan tashqari, sizeof (int) , ehtimol OP uchun muammo bo'lmaydi, chunki uning sozlashida mijoz va server ikkala x86 yoki ikkala x64 bo'ladi.
qo'shib qo'ydi muallif Mints97, manba