Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Socket: введение в сетевые коммуникации
Socket (сокет) — это абстракция для создания сетевых соединений. Это конечная точка сетевого подключения, через которую приложения обмениваются данными по сети. Проще говоря, сокет — это "телефонная розетка" для программ, позволяющая им общаться друг с другом.
Типы сокетов
1. TCP сокеты (SOCK_STREAM)
Надёжная, потокоориентированная передача данных.
import socket
# Создание TCP сокета
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# AF_INET = IPv4
# SOCK_STREAM = TCP (с гарантией доставки)
# Клиент — подключение к серверу
sock.connect(('example.com', 80))
sock.send(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
data = sock.recv(1024) # Получить до 1024 байт
print(data.decode())
sock.close()
# Сервер — прослушивание и принятие соединений
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.bind(('localhost', 5000)) # Привязка к порту
server_sock.listen(5) # Очередь из 5 соединений
print("Ожидание входящих соединений...")
client_sock, address = server_sock.accept() # Блокирующий вызов
print(f"Соединение от {address}")
data = client_sock.recv(1024)
print(f"Получено: {data.decode()}")
client_sock.send(b'Hello from server')
client_sock.close()
server_sock.close()
2. UDP сокеты (SOCK_DGRAM)
Быстрая, но ненадёжная передача данных (без гарантии доставки).
import socket
# UDP сокет
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# SOCK_DGRAM = UDP (без гарантии доставки)
# UDP клиент
sock.sendto(b'Hello', ('localhost', 5000))
data, address = sock.recvfrom(1024) # Получить с адресом отправителя
print(f"От {address}: {data.decode()}")
# UDP сервер
server_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_sock.bind(('localhost', 5000))
while True:
data, address = server_sock.recvfrom(1024)
print(f"От {address}: {data.decode()}")
server_sock.sendto(b'Ack', address) # Отправить ответ
Различия TCP vs UDP
TCP (SOCK_STREAM):
✓ Надёжная доставка
✓ Порядок сохраняется
✓ Соединение ориентировано
✗ Медленнее
✗ Больше overhead
Применение: HTTP, FTP, SSH, Telnet, Email
UDP (SOCK_DGRAM):
✓ Быстро
✓ Низкий overhead
✗ Нет гарантии доставки
✗ Может быть потеря пакетов
✗ Может быть дублирование
Применение: VoIP, Video streaming, Online games, DNS
Жизненный цикл TCP сокета
На стороне сервера
1. socket() — создание сокета
2. bind() — привязка к адресу и порту
3. listen() — переход в режим прослушивания
4. accept() — ожидание и принятие подключения
5. send()/recv() — обмен данными
6. close() — закрытие сокета
На стороне клиента
1. socket() — создание сокета
2. connect() — подключение к серверу
3. send()/recv() — обмен данными
4. close() — закрытие сокета
Практический пример: простой чат
# server.py
import socket
import threading
class ChatServer:
def __init__(self, host='localhost', port=5000):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clients = [] # Список подключённых клиентов
def start(self):
self.sock.bind((self.host, self.port))
self.sock.listen(5)
print(f"Сервер запущен на {self.host}:{self.port}")
while True:
client_sock, address = self.sock.accept()
print(f"Новое соединение от {address}")
self.clients.append((client_sock, address))
# Обработка клиента в отдельном потоке
thread = threading.Thread(
target=self.handle_client,
args=(client_sock, address)
)
thread.daemon = True
thread.start()
def handle_client(self, client_sock, address):
try:
while True:
data = client_sock.recv(1024)
if not data:
break # Клиент отключился
message = data.decode()
print(f"{address}: {message}")
# Отправить сообщение всем клиентам
self.broadcast(f"{address}: {message}")
except Exception as e:
print(f"Ошибка от {address}: {e}")
finally:
client_sock.close()
self.clients.remove((client_sock, address))
print(f"Соединение с {address} закрыто")
def broadcast(self, message):
"""Отправить сообщение всем клиентам"""
for client_sock, _ in self.clients:
try:
client_sock.send(message.encode())
except Exception as e:
print(f"Ошибка при отправке: {e}")
if __name__ == '__main__':
server = ChatServer()
server.start()
# client.py
import socket
import threading
class ChatClient:
def __init__(self, host='localhost', port=5000):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def connect(self):
self.sock.connect((self.host, self.port))
print(f"Подключено к {self.host}:{self.port}")
# Поток для получения сообщений
receive_thread = threading.Thread(target=self.receive_messages)
receive_thread.daemon = True
receive_thread.start()
# Основной поток для отправки сообщений
self.send_messages()
def receive_messages(self):
while True:
try:
data = self.sock.recv(1024)
if data:
print(f"\n{data.decode()}")
print("> ", end="", flush=True)
except Exception as e:
print(f"Ошибка при получении: {e}")
break
def send_messages(self):
while True:
message = input("> ")
if message.lower() == 'exit':
self.sock.close()
break
try:
self.sock.send(message.encode())
except Exception as e:
print(f"Ошибка при отправке: {e}")
break
if __name__ == '__main__':
client = ChatClient()
client.connect()
Асинхронные сокеты с asyncio
import asyncio
async def handle_client(reader, writer):
"""Обработка одного клиента"""
addr = writer.get_extra_info('peername')
print(f"Соединение от {addr}")
try:
while True:
data = await reader.read(1024)
if not data:
break
message = data.decode()
print(f"{addr}: {message}")
# Отправить ответ
writer.write(f"Echo: {message}".encode())
await writer.drain()
finally:
writer.close()
await writer.wait_closed()
print(f"Соединение с {addr} закрыто")
async def main():
server = await asyncio.start_server(
handle_client,
'localhost',
5000
)
async with server:
await server.serve_forever()
if __name__ == '__main__':
asyncio.run(main())
Практические примеры использования сокетов
# 1. Простой HTTP клиент
import socket
def http_get(url):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('example.com', 80))
sock.send(b'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n')
response = b''
while True:
data = sock.recv(4096)
if not data:
break
response += data
sock.close()
return response.decode()
# 2. Проверка открытого порта
def is_port_open(host, port, timeout=2):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
try:
result = sock.connect_ex((host, port))
return result == 0
finally:
sock.close()
# 3. DNS запрос
import socket
ip = socket.gethostbyname('example.com')
print(f"IP: {ip}")
hostname = socket.gethostbyaddr('8.8.8.8')
print(f"Hostname: {hostname}")
Важные параметры и опции
# Таймаут на операции
sock.settimeout(5.0) # 5 секунд
# Отключить Nagle алгоритм (для минимальной задержки)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
# Размер буфера
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
# Переиспользовать адрес (для быстрого перезапуска сервера)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Keep-alive (для долгоживущих соединений)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
Заключение
Socket — это фундаментальный механизм для сетевого программирования. Понимание того, как работают сокеты, критически важно для разработки масштабируемых сетевых приложений, от простых чатов до высоконагруженных серверов. Для современного Python разработчика рекомендуется использовать высокоуровневые библиотеки (asyncio, httpx, websockets), но понимание низкоуровневой работы сокетов остаётся необходимым.