در این مقاله، خواهید آموخت که چگونه یک برنامه سوکت در پایتون کدنویسی کنید اما پیش از آن، لازم است درک نمایید که سوکت چیست و در چه موقعیتهایی می تواند مورد استفاده قرار گیرد.
سوکت چیست و چه کاربردی دارد؟
میتوان سوکت را بهعنوان یک اتصال سریع تعریف کرد که امکان انتقال داده میان دو فرایند را، روی یک ماشین یا ماشینهای مختلف از طریق شبکه واحد، فراهم میسازد. سوکت معمولاً در تعاملات کلاینت-سرور (Client-Server) مورد استفاده قرار میگیرد زیرا به برنامهها اجازه میدهد تا از طریق مکانیزمهای داخلی سختافزار و سیستمعامل، با یکدیگر ارتباط برقرار کنند.
تصویر(1)
بسیاری از نرمافزارهای پرکاربرد امروزی، مانند مرورگرها، نرمافزارهای اشتراکگذاری فایل، برنامههای پیامرسان فوری مانند واتساپ و غیره… ذاتا به مفهوم سوکت وابسته هستند.
معمولاً یک برنامه سوکت شامل دو برنامه اصلی با نامهای کلاینت و سرور است. در اینجا، کلاینت نقش درخواستدهنده را ایفا نموده و دادهای را درخواست میکند. سرور نقش شنونده را دارد و داده درخواستی را بهعنوان پاسخ برای کلاینت ارسال می نماید. برنامه نویسی سوکت با پایتون و ایجاد یک برنامه کلاینت و سرور کار سادهای است زیرا پایتون ماژولهای پیشفرض بسیاری برای کمک به این کار در اختیار دارد.
نحوه کدنویسی سرور با سوکت در پایتون
در ابتدا برای نوشتن سوکت در پایتون، باید برنامه سرور خود را کدنویسی کنید. برای ساده نگه داشتن موضوع، فرض نمایید که سرور به میزبانی مشخص در یک پورت خاص گوش میدهد و هر دادهای که دریافت میکند را چاپ کرده و در پاسخ، تعدادی حروف تصادفی ASCII ارسال مینماید.
# server.py
# وارد کردن ماژولهای درونساخت ضروری
import socket
import random
import string
# ایجاد یک نمونه از سوکت
server_object = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# اتصال به میزبان محلی (localhost)
ip_address = '127.0.0.1'
port = 5555
server_object.bind((ip_address, port))
server_object.listen()
# هنگامی که کلاینت به پورت مشخص متصل میشود، سرور شروع به پذیرش درخواست میکند
connection_object, _ = server_object.accept()
if connection_object:
# اتصال موفق به کلاینت
print("SERVER CONNECTED TO CLIENT")
# ارسال پیام اولیه به کلاینت
connection_object.send(b"type the message")
# دریافت پیام از کلاینت
data_receive = connection_object.recv(1024)
while data_receive != b'stop':
print("{}: {}".format("CLIENT MESSAGE: ", data_receive.decode('utf-8')))
server_input = random.choice(string.ascii_letters)
connection_object.send(server_input.encode('utf-8'))
data_receive = connection_object.recv(1024)
در کد بالا، یک نمونه از سوکت برای سرور ایجاد شده است. همانطور که مشاهده میشود، family=socket.AF_INET مشخص میکند که خانواده آدرس مورد استفاده در این سوکت، فقط آدرسهای IPv4 خواهند بود. همچنین type=socket.SOCK_STREAM تعیین می نماید که این سوکت تنها اتصالات TCP (پروتکل کنترل انتقال) را میپذیرد.
برای اینکه سوکت سرور بتواند به درخواستها گوش دهد و آنها را بپذیرد، نیاز به آدرس IP و یک پورت دارد. بنابراین ip_address = '127.0.0.1' و port = 5555 تعیین شده است. در این کد، آدرس IP به صورت localhost انتخاب شده زیرا سرور و کلاینت روی یک ماشین قرار دارند.
در گام بعدی این برنامه نویسی سوکت با پایتون، شی سرور (server_object) یک آدرس را برقرار (bind) میکند تا کلاینتها بتوانند از آن برای یافتن سرور استفاده کنند. متد bind ((ip_address, port)) صریحا یک آدرس IP محلی و شماره پورت به شی سرور تخصیص خواهد داد، بهطوری که برنامه سرور روی همان پورت، شنود (listen) انجام میدهد. برای این کار، باید یک پورت و آدرس IP محلی به سرور اختصاص داده شود.
سپس سرور شروع به گوش دادن فعالانه روی پورت مشخصشده میکند. وقتی کلاینت از سمت خود به این پورت متصل میشود، سرور درخواست اتصال از سمت کلاینت را میپذیرد. در ادامه، یک شیء جدید به نام connection_object ایجاد میگردد و به سرور بازگردانده میشود.
این شیء connection_object شامل تمام اطلاعات لازم درباره سرور و کلاینت است. اکنون با استفاده از همین شیء، سرور میتواند پیامی به کلاینت ارسال کند. در صورت ایجاد موفق این شیء، پیغام "SERVER CONNECTED TO CLIENT" چاپ میشود. پس از ایجاد connection_object، این شیء یک پیام اولیه با نام type the message را بهصورت بایت برای کلاینت ارسال میکند و سپس منتظر دریافت پیام از کلاینت میماند.
در حلقه while، شیء connection_object پیام کلاینت را چاپ میکند و در پاسخ، یک حرف تصادفی ASCII را ارسال کرده و مجدداً منتظر پیام جدیدی از کلاینت میماند. این حلقه تا زمانی اجرا خواهد شد که کلاینت پیامی با محتوای stop ارسال کند.
نحوه کدنویسی کلاینت با socket در پایتون
تا اینجا، کدنویسی سمت سرور بررسی شد. اکنون به کدنویسی سمت کلاینت که نسبتاً ساده است، پرداخته می شود.
client.py
# وارد کردن ماژول سوکت
import socket
# ایجاد نمونهای از سوکت
client_object = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# آدرس IP هدف و پورت
ip_address = '127.0.0.1'
port = 5555
# نمونه، درخواستی برای اتصال به آدرس و پورت مشخصشده ارسال میکند
client_object.connect((ip_address, port))
# دریافت پاسخ از سرور
data_receive = client_object.recv(1024)
# اگر پاسخ دریافتی خالی نباشد
if data_receive:
# اتصال با موفقیت انجام شده است
print("CLIENT CONNECTED TO SERVER")
print(data_receive.decode('utf-8'))
while data_receive:
# دریافت ورودی از کاربر
client_input = input().encode('utf-8')
# ارسال درخواست به سرور
client_object.send(client_input)
# دریافت پاسخ از سرور
data_receive = client_object.recv(1024)
if data_receive:
print("{}: {}".format("SERVER", data_receive.decode('utf-8')))
در کد کلاینت، یک شیء سوکت به نام client_object ایجاد و آدرس ip_address و port هدف، مطابق با تنظیمات برنامه سرور، مشخص شده است. در گام بعدی، از نمونه client_object استفاده میشود و با استفاده از متد ()connect، به آدرس و پورت موردنظر متصل میگردد.
زمانی که اتصال با موفقیت برقرار میشود و شیء connection_object در سمت سرور ایجاد میگردد، سرور پیامی با محتوای type the message ارسال میکند که در سمت کلاینت در متغیر data_receive ذخیره میشود.
تصویر(2)
از آنجایی که سرور پیامی ارسال کرده، باید از آن برای تایید موفقیتآمیز بودن اتصال استفاده نمایید. بنابراین، پیغام "CLIENT CONNECTED TO SERVER" چاپ میشود و سپس محتوای پیام type the message نیز به نمایش در می آید.
در حلقه while، ابتدا ورودی از کاربر گرفته میشود که با تابع داخلی ()input دریافت میگردد. سپس با استفاده از متد encode('utf-8') به بایت تبدیل میشود زیرا دادهها باید بهصورت بایت ارسال شوند. این مقدار در متغیر client_input ذخیره شده و با استفاده از client_object.send(client_input) به سرور ارسال میشود.
با ارسال درخواست، پاسخی از سمت سرور دریافت میگردد. سرور پیام را دریافت کرده و یک پاسخ به کلاینت ارسال میکند. این روند تا زمانی ادامه مییابد که کاربر پیامی با محتوای stop را به سرور ارسال نماید.
نحوه اجرای فایلهای server.py و client.py
هنگام برنامه نویسی socket در پایتون، ابتدا باید برنامه سمت سرور و سپس برنامه کلاینت را اجرا کنید زیرا زمانی که کلاینت قصد اتصال دارد، باید سروری در حال اجرا و شنود در آن پورت موجود باشد.
نحوه اجرای server.py و سپس client.py بهصورت زیر خواهد بود:
تصویر(3)
همانطور که مشاهده میشود، پس از شروع اجرا، سرور پیام "SERVER CONNECTED TO CLIENT" را نمایش داد، بنابراین کاربر متوجه میشود که اتصال برقرار شده و سپس پیام اولیه را به کلاینت ارسال کرد. این نتیجه یک برنامه نویسی کلاینت سرور با پایتون است.
در سمت کلاینت، هنگامی که پیام دریافت شد، پیام "CLIENT CONNECTED TO SERVER" به نمایش درآمد و همچنین پیام دریافتی type the message چاپ گردید. از آنجایی که کلاینت در حال انتظار برای دریافت ورودی از کاربر است، بهمحض دریافت ورودی از کاربر، آن را برای سرور ارسال میکند. سرور پیام کلاینت را چاپ کرده و در پاسخ، یک حرف تصادفی ASCII به کلاینت باز میگرداند.
این روند تا زمانی تکرار شد که کلاینت پیامی با محتوای stop را بهعنوان درخواست برای سرور ارسال کرد. با دریافت این پیام، سرور از سشن سوکت در پایتون خارج شد.
جمع بندی
طی این مقاله، نحوه ایجاد یک ارتباط ساده کلاینت-سرور با استفاده از سوکت در پایتون مورد بررسی قرار گرفت. در ابتدا، مفاهیم پایه مرتبط با سوکتها تشریح گردید و سپس توسط ارائه مثالهایی از کدنویسی سمت سرور و کلاینت، فرآیند برقراری ارتباط، ارسال و دریافت داده میان دو برنامه، بهصورت عملی توضیح داده شد.
برنامه ایجاد شده نشان داد که سوکت در پایتون، بستر مناسبی برای آموزش و اجرای مفاهیم اولیه شبکه فراهم میکند. مطالب ارائهشده میتوانند زمینهساز ورود به مباحث پیشرفتهتر در حوزه برنامهنویسی شبکه از جمله توسعه سامانههای توزیعشده، برنامههای آنلاین و پروتکلهای ارتباطی سفارشی باشند.