ویرکارایی: سرور سوکت با کارایی بالا در C++

اینم یه تجربه پراکنده دیگه!

یه مدته که اینجا حرف برنامه نویسی زده نشده و میترسم «عنودان بد گهر» فکر کنن که من برنامه نویسی رو فراموش کردم. پس این دفعه سعی میکنم یه موضوع عمیق که به کارایی سرور سوکت مربوط میشه رو بنویسم.

توی یکی از پروژه‌هایی که من انجام میدادم مهمترین نیازمندی این بود که با کارایی بالا از سوکت UDP اطلاعات رو دریافت و پردازش کنم. کل پردازش یه سری عملیات به نسبت ساده ریاضی بود و کل ماجرا توی کارایی اون سوکت UDP خلاصه میشد. خب اولین راهی که پیش من بود این بود که اولا تحقیق و دوما آزمایش کنم. توی تحقیقاتم با توجه به مطلبی که توی این کتاب در مورد Nginx خونده بودم و نتیجه جستجو‌هام به این نتیجه رسیدم که بایستی بصورت Async سوکت‌ها رو مدیریت کنم. توی تحقیقاتم با توجه به معلوم نبودم پلتفرم توسعه با استفاده از Node.JS و C# نمونه‌هایی پیاده کردم و تست کردم و الحق که به نتایج قابل قبولی تو مایه‌های ۱۰۰۰ یا ۱۰۰۰۰ پکت در ثانیه رسیدم. توی C و C++ راه حل‌های متفاوتی برای این کار ارائه شده بود که بهترینش به نظرم کاری بود که توی boost::asio انجام شده بود که کلا روند async رو برای سوکت‌ها فایلها و تایمرها پیاده‌سازی کرده بود. نتیجه استفاده از این کتابخانه بسیار خوب بود و تا الان فراتر از حد نیاز کارایی رو فراهم کرده. کد هم به شدت ساده است. کل سرور در حد ۲۰ خط پیاده‌سازی شده.

اما برم سراغ یه مقدار جزئیات پیاده‌سازی که این کتابخونه از چشم من دور کرده بود. برای اینکه بتونیم کارایی خوبی داشته باشیم بایستی بتونیم با یه روندی منتظر سوکت‌ها نمونده و در صورتی که براشون اتفاق خاصی افتاد اونها رو بررسی کنیم. به این حالت بایستی یه حلقه داشته باشیم که بصورت بی‌پایان اجرا میشه و منتظر رخدادهاست که معروف به حلقه رخداد هست. همانطور که میدونید سوکت‌ها اصلتا در  کرنل مدیریت میشن و اطلاع از رخدادها رو کرنل برای ما فراهم میکنه. پس اگه بخوایم بصورت غیرهمزمان(async) اونها رو بررسی کنیم چاره‌ای نداریم که  کرنل این کار رو برای ما انجام بده. به این شکل که مکانیزمی داشته باشه که ما بتونیم بگیم که حواست به این سوکت‌ها باشه و هر وقت خبری شد خبرم کن. توی سیستم عامل‌های مختلف کرنل مکانیزم‌های متفاوتی برای این کار رو فراهم میکنه:

  • kqueue: مکانیزمی هست که توی خانواده BSD فراهم شده
  • epoll: مکانیزمی هست که توی کرنل لینوکس فراهم شده
  • event port: در سولاریس مورد استفاده قرار گرفته
  • Overlapped I/O: به پیاده سازی اختصاصی این ماجرا در ویندوز گفته میشه.
  • Input/Output Completion Port: روندی است که ویندوز و سولاریس اون رو پیاده‌سازی کردن.

البته باید بگم که برخی از این مکانیزم‌ها به سیستم عامل‌های دیگه هم پورت شدن و توی اونها هم قابل دسترسی هستند.

خب اگه ما بخوایم کدی بنویسیم که از یکی از این مکانیزم‌ها به درستی استفاده کنه و قابل پورت به سیستم عامل‌های دیگه باشه میرسیم به همون boos::asio که دقیقا همین کار رو کرده وسیستم عامل‌های مختلف رو هم پیشتیبانی میکنه. پیاده‌سازی این مکانیزم‌ها معمولا یه سختی هم داره و اون اینه که شما بایستی با system call های کرنل اون سیستم عامل آشنایی خوبی داشته باشی که در اکثر برنامه‌نویسا نیست که این باعث سخت شدن نگهداری کد میشه.

در مجموع استفاده کردن این کتابخانه‌ها که هم بخوبی تست شدن، هم ثبات کافی دارن باعث سادگی کار کاهش زمان مورد نیاز برای توسعه میشه. اما یادتون باشه که این سادگی هزینه داره و اگه یه روزی برسه این برنامه جواب کارتون رو نده شما باید آستیناتون رو بالا بزنید و کد رو یه شخم حسابی بزنید!

همین!

لذت برنامه نویسی: کتابخانه کار با سوکت در c++

اینم یه تجربه پراکنده دیگه!

یکی از کارهای متفاوتی که من میکنم اینه که توی لینوکس به زبان c++ برنامه نویسی میکنم. معمولا توی برنامه‌هایی هم که مینویسم نیاز داره که با سوکت‌های کار کنم. معمولا هم کارها طوریه که معمولا دسترسی به سوکت مهمه. من گشتم و یه سری کتابخانه برای اینکار پیدا کردم. به نظرم جالب بود که اینلیست این کتابخانه ها رو اینجا بگم.

قبل از معرفی بگم چرا به این دست کتابخانه‌ها نیازه. اولا اگه تجربه کار با سوکت‌ها رو داشته باشید میدونید در مجموع کار کردن با سوکت‌ها سخته. اولا اینکه برای ایجاد یک اتصال نیاز به انجام مقدماتی هست (مثلا تبدیل آی پی به یه قالب خاص یا تبدیل نام سایت به آی پی) همچنین یه سوکت در c++ حالت‌های گوناگونی داره که کار کردن و هندل کردن تمام این حالت‌ها معمولا کار سختیه. نکته بعدی اینه که روند کار با سوکت توی ویندوز، لینوکس و سایر سیستم‌ عامل ها متفاوت و نوشتن یه کد potable کار سخت تریه. پس معقوله شما با دادن یه هزینه معقول در زمینه کارایی و سایز کد نرم‌افزار، سطح بالاتر با سوکت سر و کله بزنی!

لیست این کتابخانه‌های اینا هستن:

  • Boost.Asio: این کتابخانه یه کتاب‌خانه سریع و خوب برای کار با سوکت‌هاست و شما به سوکت بصورت مستقیم دسترسی داری
  • ACE: از دل دانشگاه در اومده و به نظر خوب میاد. سوکت‌ها بصورت مستقیم در دسترس هستند اما عملیات‌های سطح بالاتر مثل message routing رو پشتیبانی میکنه
  • C++ Network Library: تا اونجایی که نمونه‌های و مستنداتش رو بررسی کردم این کتابخانه برای کارهای سطح بالا تر مثل http نوشته شده
  • POCO: این کتابخانه مجموعه ای از ابزارهای سطح بالا برای برنامه نویسی در اختیار شما قرار میده که شبکه و سوکت‌های یکی از اونهاست
  • Qt: این کتابخانه هم مجموعه بسیار بزرگی از ابزارها داره که یکی از اونها شبکه و سوکت هست
  • Raknet: یه کتابخانه کار با شبکه است که هم توی pc و هم توی کنسولهای بازی کاربرد داره
  • ZeroMQ: این کتابخانه بیشتر از اینکه یه کتابخانه شبکه باشه یه کتابخانه message queue هست که به شما کمک میکنه ارتباط بین چندتا اپلیکیشن رو بصورت قابل اعتمادی ایجاد کنید
  • nanomsg: این کتابخانه هم بیشتر به عنوان message queue طراحی شده
  • libevent: اصالتا یه سیستم برای پشتیبانی از سیستم‌های async هست که در جاهای بسیاری استفاده شده و بخشی از اون هم کارهای شبکه و سوکت رو انجام میده
  • Apache APR: یکی دیگر از کتابخانه‌های عموی با پشتیبانی از سوکت است
  • yield: یک کتابخانه نوشتن نرم‌افزارهای تحت وب است
  • wvstreams: یک کتابخانه قدیمی برای کار با شبکه است که سال‌هاست بروزرسانی نشده
  • libcurl: یک کتابخانه بسیار قوی برای کار با پروتکل‌های شبکه نه سوکت‌هاست که بیشتر پروتکل‌های معمول رو پشتیبانی میکنه
  • libuv: یک کتابخانه برای کار با async IO بوده که از شبکه و سوکت هم پشتیبانی میکنه. جالبه بدونید که توی nodejs هم از این کتابخانه استفاده شده.
  • SFML’s Network Module: این کتابخانه هم مثل qt یک کتابخانه چند منظوره است که از سوکت‌ها و شبکه هم پشتیبانی میکنه.

من خودم به شخصه تنها از Boost.Asio استفاده کردم و انشاا… اگه عمری بود بیشتر در مورد این کتابخانه و نمونه کدها و ویژگی‌های دیگشون مینویسم.

همین!