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

محیط و نخستین اجرا#

مثال‌های دوره با Bash روی Ubuntu و Python 3.11 یا جدیدتر نوشته شده‌اند. از شب پنجم محیط مجازی می‌سازیم؛ فعلاً فقط کتابخانهٔ استاندارد لازم است. فرمان زیر نسخهٔ مفسر را نشان می‌دهد. مفسر برنامه‌ای است که فایل پایتون را اجرا می‌کند؛ اگر فرمان پیدا نشد، باید بستهٔ Python 3 توزیع خود را نصب کنید.

python3 --version
mkdir -p ~/python-backend/night-01
cd ~/python-backend/night-01

فایل service_check.py را در این پوشه بسازید و کد زیر را داخل آن بگذارید. نام فایل دلخواه است، اما پسوند .py مشخص می‌کند با کد پایتون روبه‌رو هستیم. متن پیام‌های برنامه را انگلیسی نگه داشته‌ایم تا ورودی‌ها و نتیجهٔ آزمون در تمام درس‌ها یکسان باشند.

service_name = input("Service name: ")
service_port = input("Service port: ")

print()
print("Service information received")
print(f"Name: {service_name}")
print(f"Port: {service_port}")
print(f"URL: http://localhost:{service_port}")
python3 service_check.py

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

Service name: graylog
Service port: 9000

Service information received
Name: graylog
Port: 9000
URL: http://localhost:9000

دستورهای عادی این فایل از بالا به پایین اجرا می‌شوند. input() پیام را نشان می‌دهد و منتظر فشردن Enter می‌ماند؛ سپس متن دریافت‌شده در متغیر قرار می‌گیرد. متغیر نامی است که به یک مقدار اشاره می‌کند. علامت = مقدار سمت راست را به نام سمت چپ نسبت می‌دهد. این علامت برای پرسیدن برابری دو مقدار نیست؛ مقایسه را در شب بعد یاد می‌گیریم.

تابع print() خروجی را در ترمینال می‌نویسد. فراخوانی بدون آرگومان آن یک خط خالی ایجاد می‌کند. حرف f پیش از رشته اجازه می‌دهد مقدار عبارت داخل آکولاد در متن قرار بگیرد؛ به این شکل رشتهٔ قالب‌دار یا f-string می‌گوییم. اگر f را بردارید، آکولاد و نام متغیر به همان صورت چاپ می‌شوند. همچنین پایتون به بزرگی و کوچکی حروف حساس است؛ print با Print تفاوت دارد.

متن شبیه عدد، هنوز متن است#

رشته یا str دنباله‌ای از نویسه‌هاست. خروجی input() همیشه رشته است، حتی اگر فقط رقم وارد کنید. بنابراین در برنامهٔ بالا، service_port مقدار متنی دارد. برای ساخت نشانی این کافی است، ولی برای محاسبه باید آن را تبدیل کنیم. افزودن عدد 1 به رشتهٔ "9000" خطای TypeError ایجاد می‌کند، چون جمع عدد و متن در این حالت تعریف نشده است.

hostname = "graylog01"
port = 9000
cpu_load = 23.5
tls_enabled = True

print(type(hostname))
print(type(port))
print(type(cpu_load))
print(type(tls_enabled))

به‌ترتیب نوع‌های str، int، float و bool را خواهید دید. عدد صحیح برای مقدارهایی مثل تعداد سرورها مناسب است. عدد اعشاری برای اندازه‌ای مثل درصد مصرف کاربرد دارد. مقدار بولی یکی از دو حالت True و False را نشان می‌دهد؛ این نام‌ها بدون علامت نقل‌قول نوشته می‌شوند. رشتهٔ "False" با مقدار بولی False یکسان نیست.

فایل service_config.py را بسازید تا تبدیل را هنگام دریافت داده انجام دهیم. تابع int() متن عدد صحیح را به عدد صحیح و float() متن اعشاری را به عدد اعشاری تبدیل می‌کند. برعکس، str(9000) یک نمایش متنی از عدد می‌سازد. این تبدیل‌ها داده را برای کاری که می‌خواهیم انجام دهیم آماده می‌کنند.

service_name = input("Service name: ")
port = int(input("Service port: "))
cpu_load = float(input("CPU load percentage: "))
tls_enabled = input("Enable TLS (yes/no): ").strip().lower() == "yes"

print(f"Service: {service_name}")
print(f"Port: {port}")
print(f"Next port number: {port + 1}")
print(f"CPU load: {cpu_load}%")
print(f"TLS enabled: {tls_enabled}")

روش‌های strip() و lower() به‌ترتیب فاصله‌های ابتدا و انتهای متن را حذف و حروف را کوچک می‌کنند. پس پاسخ YES نیز با yes برابر می‌شود. عبارت مقایسه یک مقدار بولی تولید می‌کند. این مثال فقط پاسخ دقیق yes را تأیید می‌کند؛ پاسخ‌هایی مثل y یا متن نامعتبر همگی False خواهند شد. بعداً اعتبارسنجی صریح‌تری می‌نویسیم.

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

دو تمرین برای تثبیت مطلب#

در register_server.py نام میزبان، آدرس IPv4 و نقش سرور را جداگانه دریافت کنید. کارت خروجی باید شامل این سه مقدار و نشانی مدیریتی مانند https://192.168.10.11 باشد. با نمونه‌های pve01 با نقش hypervisor، graylog01 با نقش logging و proxy01 با نقش reverse-proxy امتحان کنید. در این مرحله صحت آدرس بررسی نمی‌شود و هیچ اتصالی هم برقرار نمی‌کنیم.

تمرین دوم فایل storage_report.py است. نام سرور و فضای کل و مصرف‌شده را بگیرید. دو مقدار ظرفیت را به int تبدیل کنید، فضای آزاد را با تفریق و درصد مصرف را با تقسیم فضای مصرف‌شده بر کل و ضرب در صد به دست آورید. برای نمایش یک رقم اعشار از round(usage, 1) استفاده کنید. محاسبه را روی عددها انجام دهید و تنها هنگام چاپ، نتیجه را در رشته قرار دهید.

فضای کلمصرف‌شدهفضای آزاد مورد انتظاردرصد مورد انتظار
100064036064.0
20481024102450.0
50012537525.0

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

برای خودآزمایی توضیح دهید چرا input() برای محاسبه به تبدیل نیاز دارد، حرف f چه کاری انجام می‌دهد و تفاوت 9000 با "9000" چیست. پاسخ درست باید رفتار برنامه را توضیح دهد: اولی عدد است، دومی متن؛ ظاهر مشابه، عملیات یکسانی به آن‌ها نمی‌دهد. زمان تمرین به سرعت تایپ و عیب‌یابی وابسته است و جزو زمان مطالعهٔ نثر نیست.

یک اشتباه رایج این است که دو عدد را زود به رشته تبدیل کنیم و بعد انتظار جمع داشته باشیم. عبارت "10" + "5" متن "105" می‌سازد، چون جمع دو رشته به معنی کنار هم گذاشتن آن‌هاست. در مقابل 10 + 5 عدد پانزده می‌دهد. پس نوع داده فقط برچسب توضیحی نیست؛ معنای عملیات را تعیین می‌کند. در گزارش دیسک، ظرفیت را تا پایان محاسبه عدد نگه دارید و قالب‌بندی را در آخر انجام دهید.

منابع#