برنامه نویسی سوکت چیست؟ — ۵ کاربرد اصلی برنامه نویسی سوکت

در این مقاله قصد داریم در مورد برنامه نویسی سوکت صحبت کنیم. برنامه نویسی سوکت «Socket programming» به ما امکان می‌دهد تا ارتباط مستقیم و همزمان بین دو یا چند دستگاه را در شبکه برقرار کنیم، و نقش مهمی در توسعه برنامه‌های شبکه‌ای و ارتباطات بلادرنگ بازی می‌کند. این تکنیک به برنامه‌نویسان اجازه می‌دهد تا از پروتکل‌های مختلف مانند TCP و UDP برای انتقال داده‌های قابل اعتماد یا سریع استفاده کنند. در نهایت، مطالعه و یادگیری برنامه نویسی سوکت‌ها می‌تواند مهارت‌های بسیاری در توسعه نرم‌افزارهای شبکه‌ای به ما بدهد.

برنامه نویسی سوکت چیست؟

برنامه نویسی سوکت «Socket programming»، یک روش ارتباطی بین گره‌ها (Nodes) در یک شبکه است. گره‌ها می‌توانند به عنوان کلاینت‌ها (مشتری‌ها) و سرورها در نظر گرفته شوند. سرور، یک برنامه نرم‌افزاری است که منتظر درخواست‌های کلاینت‌ها می‌ماند و به فرآیندهای ورودی سرویس می‌دهد، در حالی که کلاینت، درخواست‌کننده خدمات است. کلاینت از سرور، منابعی را درخواست می‌کند و سرور به این درخواست پاسخ می‌دهد. برای برقراری ارتباط بین کلاینت و سرور، ما در هر برنامه یک سوکت ایجاد می‌کنیم و سپس این دو سوکت را به هم متصل می‌کنیم. هنگامی که اتصال سوکت برقرار شد، گره‌ها می‌توانند داده‌ها را با هم تبادل کنند.

socket

کاربردهای برنامه نویسی سوکت

برنامه‌نویسی سوکت کاربردهای بسیار گسترده‌ای در دنیای کامپیوتر و شبکه دارد. در اینجا به چند نمونه از کاربردهای مهم برنامه نویسی سوکت می‌پردازیم:

۱. ارتباط بین کلاینت و سرور: این اساسی‌ترین کاربرد سوکت‌ها است. هر برنامه‌ای که نیاز به برقراری ارتباط بین یک کلاینت (مثلاً مرورگر وب) و یک سرور (مثلاً وب سرور) دارد، از سوکت‌ها استفاده می‌کند. این شامل:

  • وب سرورها: ارسال و دریافت صفحات وب، تصاویر، ویدیوها و سایر محتوای وب.
  • سرویس‌های ایمیل: ارسال و دریافت ایمیل‌ها.
  • چت آنلاین: انتقال پیام‌های متنی در زمان واقعی بین کاربران.
  • بازی‌های آنلاین: ارتباط بین سرور بازی و کلاینت‌های متصل به آن.
  • برنامه‌های انتقال فایل: ارسال و دریافت فایل‌ها بین کلاینت و سرور (مانند FTP).
  • دسترسی از راه دور: کنترل کامپیوتر از راه دور از طریق پروتکل‌هایی مانند SSH.

۲. ارتباط بین برنامه‌ها: سوکت‌ها می‌توانند برای ارتباط بین برنامه‌های مختلف روی یک کامپیوتر یا شبکه استفاده شوند. این به برنامه‌ها اجازه می‌دهد داده‌ها را با هم به اشتراک بگذارند و با هم کار کنند.

۳. سیستم‌های توزیع‌شده: در سیستم‌های توزیع‌شده، سوکت‌ها به اجزای مختلف سیستم اجازه می‌دهند تا با هم ارتباط برقرار کنند و به طور هماهنگ کار کنند. این شامل:

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

۴. سیستم‌های نظارت: سوکت‌ها برای نظارت بر عملکرد سیستم‌ها و تجهیزات شبکه استفاده می‌شوند. مثلاً می‌توان از آن‌ها برای جمع‌آوری داده‌های حسگرها و ارسال آن‌ها به یک سرور مرکزی استفاده کرد.

۵. پروتکل‌های شبکه: بسیاری از پروتکل‌های شبکه‌ای از سوکت‌ها برای پیاده‌سازی خود استفاده می‌کنند. مثلاً، پروتکل HTTP (که وب را نیرو می‌دهد) و پروتکل FTP (برای انتقال فایل) هر دو از سوکت‌ها برای برقراری ارتباط استفاده می‌کنند.

معماری برنامه نویسی سوکت

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

اجزای اصلی معماری سوکت

  • سوکت (Socket): هسته اصلی معماری سوکت است. سوکت، یک نقطه پایانی برای برقراری ارتباط است که به یک آدرس IP و یک شماره پورت اختصاص داده می‌شود. سوکت‌ها در هر دو طرف ارتباط (کلاینت و سرور) وجود دارند.
  •  کلاینت (Client): برنامه‌ای است که درخواست‌ها را به سرور ارسال می‌کند. کلاینت یک سوکت ایجاد می‌کند و به سوکت سرور متصل می‌شود.
  • سرور (Server): برنامه‌ای است که منتظر دریافت درخواست‌ها از کلاینت‌ها است. سرور یک سوکت ایجاد می‌کند و به یک آدرس IP و شماره پورت مشخص گوش می‌دهد. هنگامی که یک کلاینت به سرور متصل می‌شود، سرور یک سوکت جدید برای ارتباط با آن کلاینت ایجاد می‌کند.
  • آدرس  (IP Address): IP یک شناسه منحصر به فرد برای یک دستگاه در شبکه است.
  • شماره پورت (Port Number): یک شماره است که برای شناسایی یک برنامه خاص در یک دستگاه استفاده می‌شود. پورت‌ها به برنامه‌ها اجازه می‌دهند که داده‌ها را از طریق یک سوکت خاص ارسال و دریافت کنند.

socket programming 1

مراحل کلی برنامه نویسی سوکت

  • ایجاد سوکت (Socket Creation): هر دو طرف ارتباط (کلاینت و سرور) یک سوکت ایجاد می‌کنند.
  • اتصال (Connection): کلاینت به سوکت سرور متصل می‌شود.
  • تبادل داده (Data Exchange): کلاینت و سرور می‌توانند داده‌ها را از طریق سوکت‌ها ارسال و دریافت کنند.
  • بستن اتصال (Connection Closure): پس از اتمام تبادل داده، سوکت‌ها بسته می‌شوند.

مزایای معماری سوکت

  • انعطاف‌پذیری: سوکت‌ها برای انواع مختلفی از برنامه‌های شبکه قابل استفاده هستند.
  • قابلیت حمل: برنامه‌های سوکت می‌توانند بر روی پلتفرم‌های مختلف اجرا شوند.
  • استاندارد: سوکت‌ها یک استاندارد جهانی برای برقراری ارتباط بین برنامه‌ها هستند.

انواع سوکت ها

سوکت های جریانی (Stream Sockets): سوکت‌های جریانی، که مبتنی بر پروتکل TCP (Transmission Control Protocol) هستند، نوعی از سوکت‌ها هستند که ارتباطی قابل اعتماد و ترتیب‌دار را بین دو نقطه پایانی فراهم می‌کنند. این نوع سوکت‌ها، به دلیل ویژگی‌های ذاتی خود، برای برنامه‌هایی که نیاز به تحویل بدون خطای داده‌ها با حفظ ترتیب دارند، بسیار مناسب هستند.

Stream Sockets

ویژگی‌های کلیدی سوکت‌های جریانی (TCP):

  • قابل اعتماد بودن (Reliability): TCP از مکانیزم‌های مختلفی برای اطمینان از تحویل بدون خطای داده‌ها استفاده می‌کند. این مکانیزم‌ها شامل:
  • کنترل خطا (Error Detection): بررسی صحت داده‌های ارسالی و تشخیص خطاها.
  • درخواست مجدد (Retransmission): ارسال مجدد بسته‌هایی که در طول انتقال گم شده‌اند یا خراب شده‌اند.
  • تاییدیه دریافت (Acknowledgement): ارسال تاییدیه از طرف گیرنده برای هر بسته دریافتی، به فرستنده اطمینان می‌دهد که داده‌ها به درستی تحویل داده شده‌اند.
  • ترتیب ارسال (Ordered Delivery): TCP تضمین می‌کند که داده‌ها به همان ترتیبی که ارسال شده‌اند، به گیرنده تحویل داده شوند. این ویژگی برای برنامه‌هایی که ترتیب داده‌ها در آن‌ها مهم است، بسیار حیاتی است.
  • کنترل جریان (Flow Control): TCP از مکانیزم‌های کنترل جریان برای جلوگیری از غرق شدن گیرنده با حجم زیاد داده استفاده می‌کند. این مکانیزم‌ها سرعت ارسال داده‌ها را با توجه به ظرفیت گیرنده تنظیم می‌کنند.
  • اتصال گرا (Connection-oriented): قبل از شروع انتقال داده‌ها، یک اتصال بین فرستنده و گیرنده برقرار می‌شود. این اتصال یک کانال اختصاصی برای ارتباط ایجاد می‌کند و امکان مذاکره و تنظیم پارامترهای ارتباط را فراهم می‌کند.

نحوه عملکرد سوکت های جریانی (TCP):

  • برقراری اتصال (Connection Establishment): قبل از شروع انتقال داده، یک فرآیند “دست دادن سه طرفه” (Three-way Handshake) بین کلاینت و سرور انجام می شود. این فرآیند یک اتصال TCP را برقرار می کند و پارامترهای ارتباط را تعیین می کند.
  • انتقال داده (Data Transfer): داده ها به صورت جریان از طریق اتصال TCP ارسال و دریافت می شوند. TCP اطمینان حاصل می کند که داده ها به طور قابل اعتماد و به ترتیب تحویل داده می شوند.
  • خاتمه اتصال (Connection Termination): پس از اتمام انتقال داده، اتصال TCP با یک فرآیند خاتمه اتصال بسته می شود.

کاربردهای رایج سوکت های جریانی (TCP):

  • مرور وب (Web Browsing): پروتکل HTTP، که برای مرور وب استفاده می شود، بر روی TCP کار می کند.
  • ایمیل (Email): پروتکل های SMTP، POP3، و IMAP، که برای ارسال و دریافت ایمیل استفاده می شوند، بر روی TCP کار می کنند.
  • انتقال فایل (File Transfer): پروتکل FTP، که برای انتقال فایل استفاده می شود، بر روی TCP کار می کند.
  • دسترسی از راه دور (Remote Access): پروتکل SSH، که برای دسترسی امن از راه دور به سیستم ها استفاده می شود، بر روی TCP کار می کند.
  • پایگاه داده ها (Databases): بسیاری از سیستم های پایگاه داده از TCP برای ارتباط بین کلاینت ها و سرور استفاده می کنند.

سوکت های دیتاگرامی (Datagram Sockets): سوکت های دیتاگرامی، که مبتنی بر پروتکل UDP (User Datagram Protocol) هستند، نوعی از سوکت ها هستند که ارتباطی غیرقابل اعتماد و بدون اتصال را بین دو نقطه پایانی فراهم می کنند. این نوع سوکت ها، به دلیل ویژگی های ذاتی خود، برای برنامه هایی که سرعت در آنها اهمیت بیشتری از قابلیت اطمینان دارد، بسیار مناسب هستند.

Datagram socket

ویژگی های کلیدی سوکت های دیتاگرامی (UDP):

  • غیرقابل اعتماد بودن (Unreliability): UDP هیچ تضمینی برای تحویل داده ها ارائه نمی دهد. بسته ها ممکن است گم شوند، خراب شوند، یا خارج از ترتیب برسند.
  • بدون اتصال (Connectionless): هیچ اتصال دائمی بین فرستنده و گیرنده قبل از انتقال داده ها برقرار نمی شود. هر بسته داده به طور مستقل ارسال می شود.
  • سرعت بالا (High Speed): به دلیل عدم وجود مکانیزم های کنترل خطا و کنترل جریان، UDP سریعتر از TCP است.
  • پخش (Broadcast): UDP از پخش پشتیبانی می کند، به این معنی که یک بسته داده می تواند به طور همزمان به چندین گیرنده ارسال شود.
  • چندپخشی (Multicast): UDP از چندپخشی پشتیبانی می کند، به این معنی که یک بسته داده می تواند به گروهی از گیرنده ها ارسال شود.

نحوه عملکرد سوکت های دیتاگرامی (UDP):

  • ارسال داده (Data Transfer): فرستنده به سادگی بسته های داده را به سمت گیرنده ارسال می کند. UDP هیچ تلاشی برای اطمینان از تحویل داده ها انجام نمی دهد.
  • دریافت داده (Data Reception): گیرنده بسته های داده را دریافت می کند. اگر بسته ای گم شود یا خراب شود، گیرنده هیچ درخواستی برای ارسال مجدد آن نمی کند.

کاربردهای رایج سوکت های دیتاگرامی (UDP):

  • استریمینگ ویدئو (Video Streaming): در استریمینگ ویدئو، از دست دادن چند فریم معمولاً قابل چشم پوشی است، در حالی که تاخیر می تواند تجربه کاربر را به شدت تحت تاثیر قرار دهد. UDP به دلیل سرعت بالا و عدم وجود سربار ناشی از کنترل خطا، برای استریمینگ ویدئو مناسب است.
  • بازی های آنلاین (Online Games): در بازی های آنلاین، سرعت و تاخیر کم از اهمیت بالایی برخوردار است. UDP به دلیل سرعت بالا و عدم نیاز به اتصال دائمی، برای بازی های آنلاین مناسب است.
  • VoIP (Voice over IP): در VoIP، از دست دادن چند بسته صوتی معمولاً قابل چشم پوشی است، در حالی که تاخیر می تواند کیفیت مکالمه را به شدت تحت تاثیر قرار دهد. UDP به دلیل سرعت بالا و عدم وجود سربار ناشی از کنترل خطا، برای VoIP مناسب است.
  • DNS  :(Domain Name System)DNS از UDP برای جستجوی آدرس IP مربوط به یک نام دامنه استفاده می کند.
  • پخش و چندپخشی (Broadcast and Multicast): UDP برای برنامه هایی که نیاز به ارسال داده به چندین گیرنده به طور همزمان دارند، مناسب است.

سوکت های خام (Raw Sockets): سوکت های خام، نوعی خاص از سوکت ها هستند که به برنامه ها اجازه می دهند مستقیماً با لایه شبکه (Network Layer) کار کنند و بسته های IP را با هدرهای دلخواه ایجاد و ارسال کنند. این نوع سوکت ها به طور معمول نیاز به دسترسی سطح بالا (مانند دسترسی root یا administrator) دارند و برای کاربردهای خاصی که نیاز به کنترل دقیق بر روی بسته های شبکه ای دارند، استفاده می شوند.

ویژگی های کلیدی سوکت های خام:

  • دسترسی مستقیم به لایه شبکه: برنامه ها می توانند هدرهای IP را به طور کامل کنترل کنند، از جمله آدرس مبدا و مقصد، نوع پروتکل، و سایر فیلدها.
  • توانایی دریافت بسته های IP با هر پروتکلی: برنامه ها می توانند بسته های IP را با هر نوع پروتکلی (مانند ICMP، IGMP، و غیره) دریافت کنند.
  • نیاز به دسترسی سطح بالا: برای ایجاد و استفاده از سوکت های خام، معمولاً نیاز به دسترسی root یا administrator است.
  • پیچیدگی: برنامه نویسی با سوکت های خام پیچیده تر از استفاده از سوکت های TCP یا UDP است.

کاربردهای رایج سوکت های خام:

  • بررسی امنیت شبکه (Network Security Auditing): سوکت های خام می توانند برای شبیه سازی حملات شبکه و بررسی امنیت شبکه استفاده شوند.
  • پروتکل های سفارشی (Custom Protocols): در مواردی که نیاز به پیاده سازی پروتکل های شبکه ای سفارشی وجود دارد، سوکت های خام می توانند استفاده شوند.
  • مانیتورینگ شبکه (Network Monitoring): سوکت های خام می توانند برای مانیتورینگ ترافیک شبکه و جمع آوری اطلاعات استفاده شوند.

Network Monitoring

مزایا و معایب برنامه نویسی سوکت

برنامه‌نویسی سوکت، روشی قدرتمند برای ایجاد ارتباطات شبکه‌ای است، اما مانند هر تکنولوژی دیگری، مزایا و معایبی دارد:

مزایا

  • کنترل کامل: برنامه‌نویسی سوکت به شما کنترل کاملی بر روی ارتباطات شبکه‌ای می‌دهد. شما می‌توانید پروتکل‌ها، پورت‌ها و سایر جزئیات ارتباط را به‌طور دقیق کنترل کنید. این امر به شما امکان می‌دهد تا ارتباطات سفارشی و بهینه‌سازی شده برای برنامه‌هایتان ایجاد کنید.
  • انعطاف‌پذیری: سوکت‌ها می‌توانند برای ایجاد انواع مختلفی از ارتباطات، از جمله ارتباط‌های TCP (اتصال‌گرا و قابل اعتماد) و UDP (غیر اتصال‌گرا و بدون تضمین تحویل) استفاده شوند. این انعطاف‌پذیری، سوکت‌ها را برای طیف وسیعی از کاربردها مناسب می‌کند.
  • پشتیبانی گسترده: سوکت‌ها به طور گسترده در اکثر زبان‌های برنامه‌نویسی و سیستم عامل‌ها پشتیبانی می‌شوند. این به شما امکان می‌دهد تا برنامه‌های شبکه‌ای را با استفاده از زبان و پلتفرم مورد نظرتان توسعه دهید.
  • کارایی: در مقایسه با برخی از روش‌های ارتباطی سطح بالاتر، سوکت‌ها می‌توانند بسیار کارآمدتر باشند. زیرا از لایه‌های میانی اضافی استفاده نمی‌کنند.
  • قابلیت انتقال: برنامه‌های سوکتی به طور نسبی قابل انتقال هستند، به این معنی که می‌توان آنها را با تغییرات اندکی بر روی سیستم عامل‌های مختلف اجرا کرد.
  • بهینه‌سازی: امکان بهینه‌سازی ارتباطات شبکه‌ای را برای برنامه‌های خاص فراهم می‌کند.

معایب

  • پیچیدگی: برنامه‌نویسی سوکت می‌تواند نسبتاً پیچیده باشد، به ویژه زمانی که با مسائل مربوط به مدیریت خطا، امنیت و عملکرد مواجه می‌شوید. درک مفاهیم شبکه مانند آدرس‌های IP، پورت‌ها و پروتکل‌ها ضروری است.
  • مدیریت خطا: مدیریت خطا در برنامه‌های سوکتی می‌تواند چالش‌برانگیز باشد. اتصالات می‌توانند قطع شوند، داده‌ها می‌توانند گم شوند و خطاهای شبکه‌ای می‌توانند رخ دهند. برنامه‌نویس باید این موارد را در نظر گرفته و کد مناسب را برای مدیریت این خطاها بنویسد.
  • امنیت: برنامه‌های سوکتی به طور پیش‌فرض امن نیستند. برای ایجاد ارتباطات امن، باید از مکانیسم‌های امنیتی مانند رمزنگاری SSL/TLS استفاده شود. پیاده‌سازی این مکانیسم‌ها به دانش تخصصی در امنیت شبکه نیاز دارد.
  • وابستگی به پلتفرم: اگرچه نسبتا قابل انتقال هستند، اما ممکن است تغییرات کوچکی برای تطبیق با سیستم عامل های مختلف لازم باشد.
  • بهینه‌سازی دشوار: بهینه‌سازی برنامه‌های سوکتی برای دستیابی به حداکثر عملکرد، می‌تواند بسیار چالش‌برانگیز باشد.

برنامه نویسی سوکت در زبان ++C

کتابخانه‌های اصلی برای برنامه‌نویسی سوکت در سی پلاس پلاس

  • <sys/socket.h>: این سرآیند (header) معمولاً در سیستم‌عامل‌های مبتنی بر یونیکس (مانند لینوکس و macOS) برای استفاده از توابع سوکت در سطح سیستم‌عامل ضروری است.
  • <netinet/in.h>: این سرآیند شامل تعریف ساختارهایی برای آدرس‌های اینترنتی (مثل sockaddr_in برای IPv4 و sockaddr_in6 برای IPv6) و توابعی برای تبدیل آدرس‌ها و شماره پورت‌ها است.
  • <arpa/inet.h>: این سرآیند شامل توابعی برای تبدیل آدرس‌های IP (مانند inet_pton و inet_ntop) بین فرمت‌های رشته‌ای و باینری است.
  • Windows.h (در ویندوز): در ویندوز، برای برنامه‌نویسی سوکت از Winsock (Windows Sockets) استفاده می‌شود. این کتابخانه توابع مشابهی با توابع سوکت در یونیکس ارائه می‌دهد. برای استفاده از Winsock، باید سرآیند Windows.h را شامل کنید و کتابخانه ws2_32.lib را به پروژه خود اضافه کنید.

مثال ساده (TCP سرور) در سی پلاس پلاس (با استفاده از کتابخانه سوکت‌های یونیکس)

#include <iostream>
#include <string>
#include <cstring>  // for memset
#include <unistd.h> // for close
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    std::string hello = "Hello from server";

    // ۱. ایجاد سوکت
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // ۲. تنظیم آدرس سرور
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;  // Bind to all available interfaces
    address.sin_port = htons(PORT);

    // ۳. Bind
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // ۴. Listen
    if (listen(server_fd, 3) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    std::cout << "Listening on port " << PORT << std::endl;

    // ۵. Accept
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept failed");
        exit(EXIT_FAILURE);
    }

    // ۶. Read data from client
    int valread = read(new_socket, buffer, BUFFER_SIZE);
    std::cout << "Received: " << buffer << std::endl;

    // ۷. Send message to client
    send(new_socket, hello.c_str(), hello.length(), 0);
    std::cout << "Hello message sent\n";

    // ۸. Close sockets
    close(new_socket);
    close(server_fd);

    return 0;
}

مثال ساده (TCP کلاینت) در سی پلاس پلاس (با استفاده از کتابخانه سوکت‌های یونیکس)

#include <iostream>
#include <string>
#include <cstring> // for memset
#include <unistd.h> // for close
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    std::string hello = "Hello from client";

    // ۱. Create socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket failed");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // ۲. Convert IPv4 and IPv6 addresses from text to binary form
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        return -1;
    }

    // ۳. Connect to server
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connect failed");
        return -1;
    }

    // ۴. Send message to server
    send(sock, hello.c_str(), hello.length(), 0);
    std::cout << "Hello message sent\n";

    // ۵. Read data from server
    int valread = read(sock, buffer, BUFFER_SIZE);
    std::cout << "Received: " << buffer << std::endl;

    // ۶. Close socket
    close(sock);

    return 0;
}

توضیحات:

  • شامل سرآیندها: ابتدا سرآیندهای لازم برای توابع سوکت (مانند <sys/socket.h>, <netinet/in.h>, و <unistd.h>) را شامل می‌کنید.
  • تعریف ثابت‌ها: یک پورت و اندازه بافر را تعریف می‌کنید.

سرور

  • ایجاد سوکت: ()socket برای ایجاد یک سوکت TCP استفاده می‌شود.
  • تنظیم آدرس: sockaddr_in تنظیم می‌شود تا آدرس IP (همه آدرس‌ها با INADDR_ANY) و شماره پورت سرور را مشخص کند.
  • Bind() :Bind سوکت را به آدرس و پورت مشخص شده متصل می‌کند.
  • Listen() :Listen سرور را در حالت گوش دادن قرار می‌دهد و منتظر اتصالات کلاینت‌ها می‌شود.
  • Accept() :Accept یک اتصال ورودی را قبول می‌کند و یک سوکت جدید برای ارتباط با کلاینت ایجاد می‌کند.
  • خواندن و نوشتن: ()read برای دریافت داده‌ها از کلاینت و ()send برای ارسال داده‌ها به کلاینت استفاده می‌شود.
  • بستن سوکت‌ها: ()close سوکت‌های ایجاد شده را می‌بندد.

برنامه‌نویسی سوکت در زبان C

این مثال یک سرور و کلاینت ساده TCP را نشان می‌دهد که پیامی را رد و بدل می‌کنند.

سرور (server.c):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};

    // ایجاد سوکت
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // متصل کردن سوکت به آدرس
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // گوش دادن برای اتصالات
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // پذیرش اتصال
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // دریافت پیام
    read(new_socket, buffer, BUFFER_SIZE);
    printf("Received: %s\n", buffer);

    // ارسال پیام
    send(new_socket, buffer, strlen(buffer), 0);

    // بستن سوکت
    close(new_socket);
    close(server_fd);
    return 0;
}

کلاینت (client.c):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    const char *hello = "Hello from client";

    // ایجاد سوکت
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation error");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // تبدیل آدرس IP
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        return -1;
    }

    // اتصال به سرور
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection Failed");
        return -1;
    }

    // ارسال پیام
    send(sock, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    // دریافت پیام
    valread = read(sock, buffer, BUFFER_SIZE);
    printf("%s\n", buffer);

    // بستن سوکت
    close(sock);
    return 0;
}

برنامه نویسی سوکت در زبان پایتون

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

import socket

# سرور
def server():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('localhost', 8080))
    s.listen(1)
    conn, addr = s.accept()
    data = conn.recv(1024).decode()
    print(f"Received: {data}")
    conn.send(data.encode())
    conn.close()
    s.close()

# کلاینت
def client():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('localhost', 8080))
    message = "Hello from client!"
    s.send(message.encode())
    data = s.recv(1024).decode()
    print(f"Received: {data}")
    s.close()

# اجرا
if __name__ == "__main__":
    import threading
    server_thread = threading.Thread(target=server)
    server_thread.start()
    client()
    server_thread.join()

سخن آخر

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


سوالات متداول


سوکت چیست و چرا در برنامه نویسی شبکه استفاده می شود؟

سوکت یک نقطه پایانی ارتباطی در یک شبکه است. به بیان ساده، سوکت یک رابط نرم افزاری است که به برنامه ها اجازه می دهد از طریق یک شبکه ارتباط برقرار کنند. از سوکت ها برای ایجاد اتصالات و انتقال داده ها بین دستگاه ها یا فرآیندهای مختلف در یک شبکه استفاده می شود.

دو نوع اصلی سوکت کدامند؟ تفاوت آنها چیست؟

دو نوع اصلی سوکت عبارتند از: سوکت های جریانی (Stream Sockets): از پروتکل TCP (Transmission Control Protocol) استفاده می کنند. ارتباطات قابل اعتماد و منظم را ارائه می دهند. مانند یک خط تلفن عمل می کنند که تضمین می کند داده ها به ترتیب درست و بدون خطا تحویل داده شوند. سوکت های دیتاگرامی (Datagram Sockets): از پروتکل UDP (User Datagram Protocol) استفاده می کنند. ارتباطات غیرقابل اعتماد و بدون اتصال را ارائه می دهند. مانند ارسال نامه عمل می کنند که ممکن است گم شود یا خارج از ترتیب برسد.

پورت (Port) چیست؟

پورت یک عدد 16 بیتی است که یک نقطه پایانی خاص را در یک دستگاه در یک شبکه مشخص می کند. به طور خلاصه، پورت یک “کانال” برای ارتباطات است. هر برنامه یا سرویسی که از شبکه استفاده می کند، معمولاً به یک پورت اختصاص داده می شود.

تابع ()bind چه کاری انجام می دهد؟

تابع ()bind یک سوکت را به یک آدرس IP و پورت خاص متصل می کند. این کار معمولاً در سمت سرور انجام می شود تا سرور بداند به کدام آدرس و پورت گوش دهد.

چگونه داده ها را از طریق یک سوکت ارسال و دریافت می کنیم؟

برای ارسال داده ها از تابع ()send یا ()sendto (برای سوکت های UDP) استفاده می شود. برای دریافت داده ها از تابع ()recv یا ()recvfrom (برای سوکت های UDP) استفاده می شود.

میزان رضایتمندی
لطفاً میزان رضایت خودتان را از این مطلب با دادن امتیاز اعلام کنید.
[ امتیاز میانگین 0 از 0 نفر ]
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع و مراجع:
geeksforgeeks builtin مجله پی‌استور

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

پیمایش به بالا