آشنایی با سوکت های شبکه در سی و لینوکس - بخش هشتم

در نوشته پیشین تا اندازه ای درباره ساخت پیغام در سوکت های TCP و چالش پیش رو گفتیم. چالشی که بررسی شد، اندازه (Length) یک پیام یا داده فرستاده شدنی بود. چالش دیگری که پیش خواهد آمد، ترتیب بایت ها است. در نوشته زیر درباره دو مفهوم Big Endian و Little Endian گفتگو کردیم.

https://virgool.io/@linux_internals/%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-little-endian-%D9%88-big-endian-rt5c3ailish0

همچنین در سری نوشته های "آشنایی با سوکت های شبکه در سی و لینوکس" درباره مفهوم Network Byte Order گفتیم که برای استاندارد سازی بایت های فرستاده شده در شبکه، از الگوی Big Endian کمک گرفته می شود تا مستقل از سیستم عامل یا سیستم های دو سوی شبکه، یک شیوه برای ترتیب بایت های شبکه به کار گرفته شود.

حتی با به کارگیری از struct برای ساخت پیام ها برای پوشش اندازه پیام، بازهم ایرادی پیش خواهد آمد و این است که اگر قاعده ای پذیرفته شده برای ترتیب بایت شبکه نباشد، با اینکه داده ای درست به سوی دیگر فرستاده می شود ولی در سوی دیگر چون داده به گونه ای دیگری تفسیر و درک می شود، زیرا ترتیب بایت را متفاوت است.

هچنین در نوشته های پیشین درباره چهار تابع به نام های ()htons و ()htonl و ()ntohs و ()ntohl گفته ایم که به ترتیب دو تای نخست برای تبدیل داده ها قابل خواندن برای کاربر به ترتیب بایت های شبکه (Big Endian) و دو تای پایانی برای تبدیل بایت های شبکه به نمایش قابل خوانده شدن توسط کاربر به کار گرفته می شوند.

یادآوری: آنهایی که پایان نامشان s دارند برای داده های short که ۱۶ بیتی (۲ بایت) و آنهایی که l دارند برای داده های long که ۳۲ بیت (۴ بایت) هستند.
msgStruct.dep = htonl(deposit);
msgStruct.wd = htonl(withdrawals);
send(s, msgStruct, sizeof(msgStruct), 0);
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%DB%8C%DA%A9%D9%85-wbohvfgswvmm
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-e4ku3bqi7tsj
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%D8%B3%D9%88%D9%85-lb8d7ce5sqig
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%DA%86%D9%87%D8%A7%D8%B1%D9%85-fi6jlgdjlwjt
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%D9%BE%D9%86%D8%AC%D9%85-ephuzqarrm9c
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%D8%B4%D8%B4%D9%85-siqfddwwsbd4
https://virgool.io/linux-internals/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B3%D9%88%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D8%A8%DA%A9%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C-%D9%88-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D8%A8%D8%AE%D8%B4-%D9%87%D9%81%D8%AA%D9%85-xs4cc4nzktkt

هم تراز سازی و Padding

آنچه که از نوشته بخش هفتم تا کنون گفته شده است، درباره پیغام هایی است که میان دو سوی شبکه تبادل می شوند. در واقع می خواهیم پیام هایی را میان دو برنامه (یا فرایند) تبادل کنیم که از راه سوکت ها در روی شبکه با یکدیگر ارتباط دارند.

این پیام رسانی (Message Passing) تنها برای دو فرایند یا برنامه بر روی دو رایانه در شبکه نیست و درون یک سیستم با چندین پردازنده (یا هسته) یا درون یک سیستم توزیع شده می تواند که نیاز باشد تا فرایندها با یکدیگر تبادل پیام بکنند.

بنابراین در چنین موردهایی، باید در سطح برنامه (Application Layer) فرمت پیام بی ابهام شناسانده شده باشد و در بخش هفتم نشان دادیم که در زبان های سی و سی پلاس پلاس این کار (ساخت پیام با فرمت بی ابهام) به کمک struct انجام می شود.

زمانی که پیام دارای چندین فیلد کد شده دودویی باشد، باید مفهومی به نام هم تراز سازی را در نظر بگیریم. هم تراز سازی داده ها یا ساختارهای داده (Data Structure Alignment)، نحوهٔ چینش و دسترسی به اطلاعات حافظه رایانه رایانه توسط پردازندهٔ رایانه است.

در زبان های برنامه نویسی هر شی (متغیر) دارای دو شناسه مقدار و آدرس فضای حافظه اصلی است. داده ها در حافظه اصلی می توانند در اندازه های ۱، ۲، ۴، ۸ بایت یا به طور کلی توان هایی از دو نگهداری شوند. برای نمونه، می خواهیم در کنار مقدارهای int و ۴ بایتی سپرده و پرداخت ها، می خواهیم شمارِ تراکنش های سپرده ها و برداشت ها را با دو فیلد short int که هر یک ۲ بایت را اشغال می کنند، به گیرنده بفرستیم.

توجه کنید برای این short int را برگزیدیم، زیرا که شمار سپرده ها و برداشتی ها بیش از ۶۵۵۳۵ نمی شود. بنابراین چیدمان یا تراز پیام دلخواه ما بدین گونه است که: ۴ بایت برای اندازه سپرده، ۲ بایت برای شمار تراکنش های سپرده، ۴ بایت برای پرداشت ها و در پایان ۲ بایت برای شمار تراکنش های برداشتی ها را در خود دارد.

Message Alignment
Message Alignment
struct {
        int centsDeposited;
        unsigned short numDeps;
        int centsWithdrawn;
        unsigned short numWd;
} msgBuf;
// struct member value assignment
send(s, &msgBuf, sizeof(msgBuf), 0);

اندازه این struct باید ۱۲ بایت باشد ولی باید گفت که همیشه ماشین ها این (پیام) ۱۲ بایت را نمی سازند، بلکه ۱۴ بایت را خواهند ساخت. این دو بایت مازاد را Padding Bytes می گویند که در ساختار بالا و درون حافظه اصلی میان numDeps و centsWithdrawn قرار می گیرد.

برای تراز کردن داده ها در حافظه، یک یا چند بایت تهی (فضای آدرس حافظه اصلی) میان آدرس های حافظه که در هنگام اختصاص حافظه برای اعضای دیگر ساختار (struct) اختصاص داده شده است (یا خالی مانده) درج می شود. این مفهوم را Padding می نامند.

چرایی اینکه این ۲ بایت مازاد پدید می اید برای این است که در پردازنده های معماری ۳۲ بیتی، پردازنده هر بار یک واژه (کلمه - Word) یا ۴ بایت را از حافظه بر می دارد. بنابراین برای برآوردن این نیاز، همیشه داده ها در ۴ بایت در حاظفه تراز می شوند. بنابراین Padding آدرس های مازاد و تهی است.

 Data Alignment with Padding Bytes
Data Alignment with Padding Bytes

راهکار برای پوشش و از میان برداشتن Padding چیست؟ راهکار بسیار ساده است و به کد نویسی باز می گردد. یک بار دیگر چرایی اینکه در دستورهای بالا Padding رخ داده است را می گوییم، زیرا دستور unsigned short numDeps را پیش از int centsWithdrawn نوشته شده است و یک فضای تهی ۲ بایتی را برای ساختن ۴ بایت نیاز خواهد داشت. پس اگر جای نوشتن متغیرها را مانند زیر تغییر دهیم دیگر Padding رخ نمی دهد.

struct {
        int centsDeposited; 
        unsigned short numDeps;
         int centsWithdrawn;
         unsigned short numWd;
} msgBuf;

بنابراین با کد بالا، چیدمان و تراز داده ها درون پیام (حافظه اصلی) به دسرتی انجام خواهد شد و اکنون پیام فرمتی همانند نخستین شکل با ۱۲ بایت را خواهد داشت.

شاد و پیروز و تندرست و بی نیاز باشید.