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

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

وقتی از یک شبکه کامپیوتری صحبت می‌کنیم، مفاهیم زیاد و بعضاً پیچیده‌ای برای انتقال داده‌ها روی کار می‌آید. اکثر زبان‌هایی که امکان برنامه‌نویسی شبکه را به ما می‌دهند، سعی کرده‌اند از این پیچیدگی کاسته و راه‌حل ساده‌ای برای ما به وجود آورند.

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

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

 

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

سوکت (socket) در حقیقت یک لینک ارتباطی بین دو پردازش (process) یا به طور دقیق‌تر بین دو نخ (thread) بوده که برنامه‌ها می‌توانند از طریق آن با یکدیگر ارتباط برقرار کنند. این دو برنامه (یا thread) می‌توانند روی یک سیستم و یا روی دو سیستم مختلف در مکان‌های متفاوت باشند؛ مهم این است که یک ارتباطی از طریق شبکه با یکدیگر داشته باشند.

سوکت‌ها به عنوان لینک‌های ارتباطی بین دو کاربر استفاده می‌شوند تا امکان انتقال اطلاعات بین آن دو فراهم شود. به عنوان مثال، یک برنامه با معماری کلاینت سروری (معماری سرویس‌دهنده – سرویس‌گیرنده یا Client-Server) را در نظر بگیرید. سرور منتظر دریافت درخواست از سمت کلاینت و در نهایت واکنش نشان دادن به آن است و سرویس‌گیرنده نیز با ارسال درخواست به سرویس‌دهنده، خدماتی را دریافت می‌کند.

در برنامه نویسی شبکه در پایتون هم از سوکت‌ها استفاده می‌کنیم؛ به همین دلیل به این کار سوکت‌نویسی با پایتون هم گفته می‌شود.

 

سوکت نویسی (برنامه‌نویسی سوکت)

هنگامی که در یک برنامه می‌خواهیم از سوکت‌ها برای برقرار کردن ارتباطات استفاده کنیم، می‌بایست سوکت نویسی (برنامه نویسی سوکت یا socket programming) کنیم.

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

 

چگونه برنامه‌نویسی شبکه را شروع کنیم ؟

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

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

برای گسترش تعداد اتصالات در یک کامپیوتر، هر سوکت را با پورت مشخصی در آن سیستم مشخص می‌کنیم. یعنی یک آدرس ip به همراه پورت مشخص‌شده‌ی آن به thread مورد نظر تخصیص خواهد یافت.

فرض کنید یک ساختمان دارای یک کدپستی اما چند طبقه است. برای هر طبقه یک شماره پلاک یا شماره واحد در نظر می‌گیرم. در این مثال، کدپستی آدرس ip بوده و پلاک (یا شماره واحد) همان پورت (port) محل مورد منظر ما می‌باشد.

 

معماری کلاینت سروری در ارتباطات شبکه

هنگامی که دو نود در یک شبکه (روی یک یا دو سیستم) بخواهند با هم ارتباط برقرار کنند، باید ساختار خاصی را رعایت کنیم. اصطلاحاً به این ساختار، معماری سرویس‌دهنده – سرویس‌گیرنده (Client – Server) گفته می‌شود.

به زبان ساده، در این معماری یکی از نودهای طرفین ارتباط سرویسی را ارائه می‌دهد و نود دیگر، می‌خواهد این سرویس یا خدماتی را دریافت کند. به نود سرویس‌دهنده اصطلاحاً سرور (Server) گفته و نود سرویس‌گیرنده به نام کلاینت یا مشتری (Client) شناخته می‌شود.

تقریباً تمام مسائل در برنامه‌نویسی شبکه به همین صورت در نظر گرفته می‌شود.

برای مثال، زمانی که شما آدرس این صفحه را در مرورگر خود باز کردید، درخواستی از سمت شما به سرور سبز دانش ارسال شده و درخواست محتوای موجود در این صفحه را کرده است. در طرف دیگر، سرور میزبان سایت ما، محتوای این صفحه (در ساختار کدهای html و css) را در پاسخ به درخواست شما، برایتان ارسال می‌کند.

در این ارتباط، کامپیوتر شما سرویس گیرنده و سرور ما سرویس دهنده بوده است.

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

 

سوکت نویسی با پایتون

برای برنامه نویسی سوکت در پایتون، می‌توان از کتابخانه socket استفاده کرد. کتابخانه socket یک کتابخانه ساده برای برقراری ارتباطات بر بستر شبکه و برنامه‌نویسی شبکه در پایتون است.

در ابتدا این کتابخانه را به برنامه خود اضافه می‌کنیم. (در کدهای برنامه کلاینت و سرور)

import socket
کار با فایل در پایتون

کار با فایل در پایتون

 

مرحله اول برنامه‌نویسی شبکه: ایجاد سوکت جدید

همان‌طور که گفته شد، برای برقراری ارتباط نیاز به یک سوکت داریم. برای ایجاد سوکت در پایتون از تابع socket() در کتابخانه اضافه شده استفاده می‌کنیم.

این تابع چهار ورودی می‌گیرد که هر چهارتای آن‌ها به صورت پیش‌فرض تعریف شده و نیازی به تعریف آن‌ها نخواهیم داشت. اما پیشنهاد می‌کنم دو مورد اولی را مشخص کنید.

s = socket.socket(socket_family, socket_type)

 

دو ورودی اول این تابع به ترتیب به صورت زیر تعریف می‌شوند:

  • socket_family : این ورودی خانواده نوع آدرس‌دهی در ارتباط شبکه را مشخص می‌کند. نوع آن یک مقدار عددی است، اما می‌توان مقادیر ثابت موجود در کتابخانه socket را نیز برای تعریف آن استفاده کرد. معمولاً ما در ارتباطات‌های عادی از مقدار ثابت socket.AF_INET برای آدرس‌دهی IP اینترنتی (Internet Protocol) نسخه 4 و از socket.AF_INET6 برای ارتباط IPv6 استفاده می‌کنیم.
  • socket_type : مشخص‌کننده نوع سوکت است. این ورودی هم یک مقدار عددی است و می‌توان برای تعریف آن از مقادیر ثابت موجود در کتابخانه استفاده کرد. نوع سوکت نشان‌دهنده نحوه اتصال بین دو نود می‌باشد. معمولاً از مقدار socket.SOCK_STREAM برای ارتباط TCP و از socket.SOCK_DGRAM برای اتصال UDP استفاده می‌شود.

 

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

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

توابع مربوط به سوکت سرور

متد bind برای تعریف آی‌پی و پورت

با استفاده از تابع bind() که روی شئ از جنس سوکت صدا زده می‌شود، آدرس IP و پورت مورد نظر را تعیین می‌کنیم. توجه داشته باشید که پورتی که وارد می‌شود باید بر روی سیستم سرور آزاد بوده و توسط برنامه دیگری استفاده نشود.

همان‌طور که می‌دانید پورت‌های 1 تا 1024 به صورت پیش‌فرض توسط سیستم عامل رزرو شده‌اند و ما می‌توانیم پورت‌های 1025 تا 65536 را بررسی کرده و یک پورت آزاد را انتخاب کنیم.

 

متد listen برای محدودیت اتصال سوکت

این تابع می‌تواند برای تعداد کانکشن‌های برقرار شده با سرور محدودیت مشخص کند. حداقل مقدار تعریف شده برای آن 0 و سقف آن با توجه به منابع سیستم سرور تعیین می‌شود. در صورتی که سرور این تعداد کانکشن را برقرار کرده باشد، در صورت دریافت درخواست برای ایجاد کانکشن جدید، آن‌را رد خواهد کرد.

ما در مثال برنامه نویسی شبکه در پایتون با سیستم چت، مقدار 1 را برای این مورد در نظر می‌گیریم.

 

متد accept برای دریافت درخواست ارتباط

این متد درخواست‌هایی که برای سرور ارسال می‌شود را دریافت کرده و در صورت توان آن را قبول خواهد کرد. برنامه بر روی تابع accept() به صورت بلاک شده خواهد ماند تا زمانی که درخواستی به سرور ارسال شود.

پس از دریافت و قبول یک ارتباط موفق (connection)، این تابع یک تاپل (tuple) را به عنوان خروجی باز می‌گرداند. این تاپل دو مقدار دارد:

  • مقدار اول حاوی شئ ارتباط (کانکشن یا connection)
  • مقدار دوم یک تاپل حاوی مشخصات کلاینت متصل شده می‌باشد.

 

توابع سوکت سمت کلاینت

متد connect برای برقراری ارتباط شبکه

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

ورودی تابع connect() یک زوج دوتایی مرتب است که آدرس IP و پورت مقصد را مشخص می‌کند.

اگر فرض کنیم آی‌پی مقصد 192.168.1.25 بوده و پورت مورد نظر ما 8650 است، آن را به صورت زیر تعریف می‌کنیم.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((192.168.1.25, 8650))

توجه کنید که ورودی یک tuple است که اولین مقدار آن می‌تواند عدد یا یک رشته (آدرس مقصد) باشد و دومین مقدار آن همواره یک عدد است.

 

توابع اصلی سوکت نویسی با پایتون

متدهای زیر را می‌توان در هر دو طرف ارتباط شبکه (سرور یا کلاینت) استفاده کرد.

متد recv برای دریافت پیام در شبکه

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

تابع recv() یک مقدار عددی به عنوان ورودی دریافت می‌کند. این عدد نشان‌دهنده تعداد حداکثر بایت‌هایی است که باید از خروجی بخواند. یعنی به وسیله آن مشخص می‌کنیم که برنامه ما حداکثر چند بایت از پیام دریافت شده را بخواند. (به این مقدار اصطلاحاً buffer size گفته می‌شود.)

این مقدار را می‌توانید با توجه به ماهیت برنامه خود، بر روی مقدار دلخواهی تنظیم کنید. همان‌طور که می‌دانید حروف انگلیسی هر کدام معادل یک بایت هستند.

خروجی تابع به صورت byte است؛ پس اگر بخواهیم آن را به عنوان یک رشته استفاده کنیم، بهتر است تابع decode() را روی آن صدا بزنیم.

 

متد send برای ارسال پیام در شبکه

این متد برای ارسال داده‌ها بر بستر ارتباط ایجاد شده در شبکه استفاده می‌شود. تابع send() یک ورودی به صورت اجباری می‌گیرد که همان اطلاعاتی است که باید به مقصد (آن سوی ارتباط TCP) ارسال شود.

ورودی تابع می‌بایست به صورت byte و با encode مشخص باشد؛ بنابراین در صورتی که بخواهیم یک رشته را ارسال کنیم، باید ابتدا بر روی رشته مورد نظر متد encode() را صدا زده و خروجی آن را ارسال کنیم.

 

recvfrom برای دریافت پیام در ارتباط UDP

اگر در برنامه نویسی شبکه با پایتون از ارتباط UDP برای ارسال داده‌ها استفاده می‌کنید، متد recvfrom() برای دریافت پیام تعریف شده است.

 

sendto برای ارسال پیام در ارتباط UDP

در سوکت نویسی با پایتون بر بستر ارتباط UDP از متد sendto() برای ارسال پیام به مقصد استفاده می‌شود. به عنوان سومین ورودی این تابع، می‌توان مقصد (زوج آدرس و پورت) را تعریف کرد.

 

بستن ارتباط شبکه با close

در ابتدای ایجاد کانکشن، ما یک کانکشن به آن طرف ارتباط ایجاد کرده و یک پورت را مشغول کرده‌ایم. با صدا زدن تابع close() روی کانکشن ایجاد شده، کانکشن را بسته و پورت را آزاد می‌کنیم. بدیهی است که این کار در انتهای کارمان صورت خواهد پذیرفت.

 

آموزش سوکت نویسی با پایتون

آموزش سوکت نویسی با پایتون

ساخت برنامه چت با پایتون

برای ساخت برنامه چت در پایتون نیاز به دو فایل مختلف داریم، اولی به عنوان سرور (server.py) و دومی به عنوان کلاینت (client.py) شناخته خواهند شد.

ایجاد سوکت سرور و اتصال به سرور

ابتدا می‌بایست در سرور یک سوکت روی پورت مورد نظر ایجاد کرده، شنود TCP را روی آن فعال کنیم. با این کار، منتظر دریافت درخواست ایجاد کانکشن می‌مانیم.

بیایید با استفاده از دستور socket() یک سوکت برای ساخت برنامه چت در پایتون ایجاد کنیم.

چون قرار هست هر دو فایل روی یک سیستم اجرا شوند و خبری از دو سیستم با دو آدرس IP متفاوت نیست، آدرس مقصد را localhost یا آدرس 127.0.0.1 معرفی می‌کنیم؛ یعنی مقصد روی همین سیستم است.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("localhost", 14200))
s.listen(1)

#Waiting For a Connection
connection, client = s.accept()

 

همچنین در سمت مشتری (client) نیز یک سوکت ایجاد کرده و تلاش می‌کنیم تا به مقصد localhost و پورتی که در سرور تعریف کرده‌ایم (در اینجا 14200) متصل شویم.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#connecting
s.connect(("localhost", 14200))

 

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

ارسال و دریافت پیام در شبکه

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

message = "Hello"
s.send(message.encode())

 

همان‌طور که گفته شد، پیام‌ها بر روی سوکت‌ها به صورت byte ارسال می‌شوند. در نتیجه می‌بایست رشته متنی را با استفاده از تابع encode() به رشته‌ی بایتی تبدیل کنیم.

می‌خواستیم پس از آن‌که پیاممان را به سرور ارسال کردیم، یک پیام تأیید از آن دریافت کنیم.

پس در ادامه، منتظر دریافت تایید از سمت سرور مانده و پیام را دریافت کنیم. این کار را به راحتی با استفاده از تابع recv() انجام خواهیم داد.

data = s.recv(32)
print(data.decode())

 

و در پایان کانکشن ایجاد شده را به کمک متد close() می‌بندیم.

#Connection Closed
s.close()

 

برای دریافت و ارسال پیام در سمت سرور، به طور کاملاً مشابه عمل خواهیم کرد. یعنی در ادامه کدهای قبلی server.py قطعه کدهای زیر را خواهیم نوشت.

print(client, 'Connected')

data = connection.recv(32)
print('Received "' + data.decode() + '"')

connection.send("Message Received!".encode())

connection.close()

 

  • در قطعه کد بالا، پس از برقراری کانکشن، اعلام می‌کنیم که یک کلاینت به سرور متصل شد و اطلاعات (آدرس IP و پورت) آن را چاپ می‌کنیم. (خط اول)
  • سپس منتظر دریافت پیام از کلاینت خواهیم ماند و پس از دریافت، آن را چاپ می‌کنیم. (خط 3 و 4)
  • بعد از آن پیام موفقیت آمیز بودن عملیات دریافت پیام را برای client ارسال می‌کنیم. (خط 6)
  • در انتها نیز ارتباط را از سمت سرور قطع می‌کنیم. (خط هشتم)

 

گرفتن ورودی در پایتون با تابع input

گرفتن ورودی در پایتون با تابع input

 

تبریک! شما به کمک سوکت نویسی در پایتون توانستید یک ارتباط کلاینت سروری ساده ایجاد کنید. به طور کلی برای داشتن یک برنامه چت در پایتون کدهای زیر را خواهیم داشت.

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

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("localhost", 14200))
s.listen(1)

#Waiting For a Connection
connection, client = s.accept()

print(client, 'Connected')

data = connection.recv(32)
print('Received "' + data.decode() + '"')

connection.send("Message Received!".encode())

connection.close()

 

کدهای کلاینت چت پایتون

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#connecting
s.connect(("localhost", 14200))

message = "Hello"
s.send(message.encode())

data = s.recv(32)
print(data.decode())

#Connection Closed
s.close()

 

سیستم چت پیشرفته

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

 

جمع‌بندی: برنامه نویسی شبکه در پایتون

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

پس از ایجاد سوکت، از ارتباطات TCP یا UDP استفاده می‌کنیم. به این منظور از متدهای recv() و send() در ارتباط TCP و از متدهای recvfrom() و sendto() در ارتباط UDP در برنامه نویسی شبکه با پایتون استفاده خواهیم کرد.

در انتهای مقاله فرآیند برنامه‌نویسی برنامه چت در پایتون را مرور کردیم و توانستیم یک برنامه چت ساده با تبادل دو پیام متنی داشته باشیم.

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

اگر می‌خواهید تمام متدهای کتابخانه socket در پایتون را بررسی کنید، به صفحه مستندات آن در سایت رسمی پایتون مراجعه کنید.