Сокети в Python. Мережеве програмування та модуль socket
Сокети – це фундаментальна концепція для забезпечення зв’язку між пристроями чи процесами через мережу. Завдяки сокетам програми можуть обмінюватися даними через різні мережеві протоколи. Сьогодні ми ознайомимось з основами сокетів і навчимося створювати прості серверні та клієнтські програми на Python.
Сокет — це кінцева точка в двосторонньому зв’язку між пристроями, свого роду телефон, на який дзвонить абонент. Він діє як міст для мережевої комунікації. Застосування сокетів можна описати ось так:
Робота з сокетами в Python здійснюється за допомогою вбудованої бібліотеки, яка підтримує обидва типи з’єднань: TCP та UDP.
У програмуванні сокетів використовуються два різновиди протоколів:
Для створення сокету вам потрібна функція socket.socket(), яка створює новий об’єкт.
import socket # Створення сокету s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
У цьому прикладі socket.AF_INET визначає адреси IPv4, а socket.SOCK_STREAM вказує тип сокета для TCP.
Якщо ви хочете використовувати UDP, то ви повинні використовувати socket.SOCK_DGRAM.
Процес підключення клієнта до сервера відбувається завдяки методу connect(), який передає IP-адресу та номер серверного порту.
# Підключаємось до сервера через IP та порт s.connect(('localhost', 01234))
Встановивши стійке з’єднання, можна передавати дані з використанням методу send() і отримувати їх, використовуючи метод recv().
# Передача даних s.send(b'Welcome, home!') # Прийом даних data = s.recv(1024) print('Received:', data.decode())
У методі recv() параметр представляє максимальний обсяг інформації, який може бути прийнятий одночасно (у байтах).
Завершивши сеанс обміну даними, сокет слід закрити з використанням методу close().
# Закриття з'єднання s.close()
Тепер нам потрібно створити базовий приклад взаємодії TCP-клієнта з сервером Python.
Код сервера
Сервер прослуховуватиме порт 01234, встановить з’єднання з клієнтами та відповість на їхні запити.
import socket # Створення сокету server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Прив'язуємо сокет до IP-адреси та порту server_socket.bind(('localhost', 01234)) # Очікування вхідних підключень (максимум 5 клієнтів у черзі) server_socket.listen(5) print('Сервер увімкнено і в режимі очікування...') while True: # Підключення client_socket, addr = server_socket.accept() print('Підключення від:', addr) # Прийом даних data = client_socket.recv(1024) print('Отримано:', data.decode()) # Відправлення повідомлення у відповідь клієнту client_socket.send(b'Hello from server!') # Закриття клієнтського з'єднання client_socket.close()
Код клієнта
Клієнт підключається до сервера через порт 01234, надсилає повідомлення та отримує відповідь.
import socket # Створюємо сокет client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Підключаємося до сервера client_socket.connect(('localhost', 01234)) # Відправляємо дані client_socket.send(b'Welcome, home!') # Отримуємо відповідь data = client_socket.recv(1024) print('Server response:', data.decode()) # Закриваємо сокет client_socket.close()
На відміну від TCP, сокети UDP не встановлюють з’єднання перед тим, як надіслати дані. Погляньмо на приклади їхньої взаємодії.
Код UDP-сервера
import socket # Створюємо сокет UDP udp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Прив'язуємо сокет до порту та IP-адреси udp_server_socket.bind(('localhost', 01234)) print('UDP-сервер запущено...') while True: # Отримуємо дані data, addr = udp_server_socket.recvfrom(1024) print('Отримано від:', addr, 'message:', data.decode()) # Відправляємо відповідь udp_server_socket.sendto(b'Привіт від UDP-сервера!', addr)
Код UDP-клієнта
import socket # Створюємо сокет UDP udp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Надсилаємо дані на сервер udp_client_socket.sendto(b'Welcome, home!', ('localhost', 01234)) # Отримуємо відповідь data, addr = udp_client_socket.recvfrom(1024) print('UDP server response:', data.decode()) # Закриваємо сокет udp_client_socket.close()
Програмування сокетів може включати різні помилки, такі як проблеми з підключенням або помилки тайм-ауту. Бібліотека сокетів Python надає кілька винятків: socket.error, socket.timeout та інші для обробки таких ситуацій. Ось приклад обробки помилки підключення:
import socket try: # Створюємо сокет і підключаємося до сервера client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 01234)) client_socket.send(b'Welcome, home!') # Отримуємо відповідь data = client_socket.recv(1024) print('Server response:', data.decode()) except socket.error as e: print(f'Socket error: {e}') finally: # Закриваємо сокет client_socket.close()
За замовчуванням сокети блокуються, тобто вони нескінченно чекають на завершення операцій. Однак ви можете встановити сокет в режим, що не блокується, або застосовувати тайм-аути.
Встановлення тайм-ауту
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) # Встановити тайм-аут за 5 секунд try: s.connect(('localhost', 01234)) s.send(b'Welcome, home!') data = s.recv(1024) print('Received:', data.decode()) except socket.timeout: print('Connection timed out') finally: s.close()
Використання неблокованого режиму
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setblocking(False) # Встановити сокет у неблокуючий режим try: s.connect(('localhost', 01234)) except BlockingIOError: print('Неблокуючий режим: Спроба підключення виконується') s.close()
Використовуючи сокетами, ви зможете створювати широкий перелік мережевих програм, включаючи веб-сервери, чати, стрімінгові сервіси та ігри. Вони підходять майже скрізь, де потрібний мережевий обмін даними. Але як і в будь-якій технології, сокети мають переваги та деякі обмеження. Почнемо з переваг.
Використання сокетів у Python дає розробникам широкі можливості для розробки мережевих програм, забезпечуючи гнучкість та контроль над з’єднаннями. Але робота з ними потребує глибокого розуміння мережевих принципів та обліку різних чинників, які можуть впливати на продуктивність і надійність. Вибір на користь сокетів залежить від конкретних вимог програми: для низькорівневого контролю вони підходять ідеально, але більш високорівневих завдань можуть знадобитися додаткові бібліотеки і фреймворки.
Сундар Пічаї, який очолює Google з 2015 року, заявив, що його компанія продовжуватиме збільшувати число…
Українські телекомунікаційні компанії та провайдери масово здають в оренду IPv4-адреси, які свого часу були виділені…
У ChatGPT додали конектори для підключення до хмарних сервісів, таких як Google Drive, Box, Dropbox,…
Співробітники управління Кіберполіції НПУ в Запорізькій області затримали 35-річного хакера, який зламав 5000 хостинг-акаунтів і…
Внутрішня команда розробників Apple у новому тематичному дослідженні виявила, що «підхід Java до управління пам’яттю…
Компанія GlobalLogic заявила, що європейський регіон відтепер очолюватиме Юлія Штукатурова, повідомили в DOU. У GlobalLogic Юлія…