برنامه نویسی 287 بازدید

اغلب برنامه‌نویسان از زبان Go در موارد متفاوتی بهره می‌گیرند. اما با صرف زمانی برای یادگیری بهتر این زبان برنامه‌نویسی و همچنین آشنایی بیشتر با این سیستم برنامه‌نویسی که به صورت توزیع یافته است، می‌توان استفاده‌های بیشتری از آن داشت. سرور چت یکی از ایده‌هایی است که می‌توان با استفاده از زبان برنامه‌نویسی Go پیاده‌سازی کرد. با این که این یک کاربرد ساده است؛ اما به عنوان یک پروژه مقدماتی نیز به قدر کافی پیچیده محسوب می‌شود.

در این نوشته یک سرور چت را از صفر تا صد طراحی می‌کنیم. کد منبع پروژه‌ای که در این راهنما معرفی می‌شود را می‌توانید در این مخزن گیت‌هاب (+) مشاهده کنید.

پیش‌نیازها

طراحی ما ویژگی‌های بسیار ساده‌ای دارد:

  • یک اتاق چت منفرد وجود دارد.
  • کاربر می‌تواند به سرور وصل شود.
  • کاربر می‌تواند نام خود را تعیین کند.
  • کاربر می‌تواند پیامی را به اتاق بفرستد و پیام برای همه کاربران اتاق منتشر می‌شود.

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

پروتکل‌ها

برای این نمونه اولیه ارتباط بین سرور و کلاینت از طریق TCP با استفاده از یک پروتکل رشته‌ای ساده صورت خواهد گرفت. امکان استفاده از بسته rpc نیز وجود داشت؛ اما بهتر است از TCP استفاده کنیم، چون اکثر برنامه‌نویسان مبتدی به ندرت به طور مستقیم با شبکه سر و کار پیدا می‌کنند.

در این پروتکل موارد زیر پیاده‌سازی می‌شود:

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

منظور از دستور، رشته‌ای است که با نام دستور آغاز می‌شود، همه پارامترها را دارد و با n\ خاتمه می‌باید.

برای نمونه برای ارسال پیام «hello»، کلاینت دستور SEND Hello\n را روی سوکت TCP ارسال می‌کند و سپس سرور، دستور MESSAGE username Hello\n را به کلاینت‌های دیگر می‌فرستد.

همه پیام‌ها را می‌توان با استفاده از ساختارهای Golang تعریف کرد:

می‌توان یک reader پیاده‌سازی کرد تا دستور را از رشته تجزیه کند و یک متد writer نوشت که دستور را مجدداً به صورت رشته دربیاورد. زبان برنامه‌نویسی Go از io.Reader و io.Writer به عنوان اینترفیس‌های داخلی استفاده می‌کند و از این رو پیاده‌سازی این متدها لزوماً اطلاع ندارد که این متدها برای جریان TCP استفاده می‌شوند.

متد writer کاملاً ساده است. switch/type بسیار خوب عمل می‌کند.

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

برای مطالعه بیشتر در این خصوص می‌توانید به منابع reader.go و writer.go مراجعه کنید.

سرور

در این بخش کار خود را با سرور چت آغاز می‌کنیم. اینترفیس سرور را می‌توان به صورت زیر تعریف کرد. ممکن است فکر کنید شاید بهتر باشد در ابتدای کار از تعریف اینترفیس آغاز نکنیم؛ اما این وضعیت مناسب‌تر است، چون باعث می‌شود تعریف رفتارها روشن‌تر باشد.

سرور با استفاده از متد ()Listen به اتصال‌های ورودی گوش می‌دهد و متدهای ()start و ()Close به ترتیب برای آغاز و متوقف کردن سرور هستند و متد ()BroadCast نیز برای ارسال دستور به کلاینت‌های دیگر استفاده می‌شود.

اینک پیاده‌سازی واقعی سرور را می‌توانید مشاهده کنید. این پیاده‌سازی کاملاً سرراست است. در واقع یک سازه client اضافه شده است تا کلاینت‌ها و نام آن‌ها را پیگیری کند.

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

متد اصلی serve برای خواندن پیام از کلاینت و مدیریت متناسب هر پیام است. از آنجا که دو متد خواندن و نوشتن پروتکل داریم، سرور صرفاً باید در سطوح بالا با پیام‌ها تعامل کند و نیازی به ارتباط با جریان بایت وجود ندارد. اگر سرور دستور SendCommand را دریافت کند، تنها کاری که انجام می‌دهد این است که پیام را به همه کلاینت‌های دیگر انتشار می‌دهد.

و در نهایت متد ()Broadcast به صورت زیر است:

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

کد کامل منبع سرور را می‌توانید در این لینک (+) مشاهده کنید.

کلاینت

در زمینه کلاینت کار خود را با اینترفیس به صورت زیر آغاز می‌کنیم:

کلاینت می‌تواند با استفاده از متد ()Dial به سرور وصل شود و متدهای ()Start و ()Close برای آغاز و متوقف کردن کلاینت هستند. ()Send برای ارسال دستور به سرور استفاده می‌شوند و ()SetName و ()SendMessage متدهای پوششی برای تعیین نام نمایشی و ارسال پیام چت هستند. در نهایت متد ()Incoming یک کانال برای بازیابی پیام‌های چت از سرور بازمی‌گرداند.

سازه کلاینت و سازنده آن را می‌توان به صورت زیر تعریف کرد. کد زیر برخی متغیرهای خصوصی دارد که conn را برای اتصال‌ها در نظر می‌گیرد و reader/writer به عنوان یک سازه پوششی برای ارسال دستورها استفاده می‌شوند.

اکثر متدها کاملاً ساده هستند. Dial اتصالی با سرور ایجاد می‌کند و سپس reader و writer پروتکل ایجاد می‌شود.

سپس متد ()Send از cmdWriter برای ارسال دستور به سرور استفاده می‌کند.

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

کد منبع کلاینت را می‌توانید در این لینک (+) مشاهده کنید.

رابط کاربری مبتنی بر متن (TUI)

با این که کدهای فوق کاملاً کاربردی هستند؛ اما مشاهده همه چیز در عمل کار دشواری محسوب می‌شود. بنابراین باید یک رابط کاربری (UI) برای کلاینت تعریف کنیم. البته اصطلاح رابط کاربری ترمینال برای منظور ما مناسب‌تر است. Go بسته‌های زیادی برای طراحی رابط کاربری ترمینال دارد؛ اما tui-go تنها بسته‌ای است که در حال حاضر از ناحیه متنی پشتیبانی می‌کند و مثال چت (+) مناسبی نیز دارد. کد آن بسیار کوتاه است و نیازی به توضیح ندارد. کد کامل را می‌توانید در این لینک (+) مشاهده کنید.

سخن پایانی

سرور چت Go یک تمرین جالب محسوب می‌شود. این راهنما باعث می‌شود که اطلاعات خود را در مورد برنامه‌نویسی شبکه با TCP مرور کنید و همچنین مواردی را در مورد رابط کاربری ترمینال بیاموزید. در مرحله بعد می‌توانیم ویژگی‌های دیگری مانند اتاق‌های چت چندکاربره با حفظ پیام‌ها و یا حتی مدیریت خطا و تست‌های واحد را نیز به این اپلیکیشن اضافه کنیم.

اگر این مطلب برایتان مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای 1 نفر

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

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