Socket: примеры (PYTHON)

Использование функции socket для сетевого взаимодействия в Python
Раздел: Сокеты, Сетевые операции
socket(family, type, proto): socket.socket

Основы функции socket

Функция socket.socket() из одноименного модуля является конструктором для создания новых объектов сокетов в Python. Она служит основным инструментом для низкоуровневого сетевого взаимодействия, позволяя реализовывать клиент-серверную архитектуру, протоколы TCP/IP, UDP и другие.

Функция используется, когда требуется прямое управление сетевым соединением: создание серверов, клиентов, обмен данными между процессами на разных машинах или реализация специализированных сетевых протоколов.

Синтаксис вызова функции: socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None).

  • family (семейство адресов): определяет пространство адресов. Основные значения: socket.AF_INET (IPv4), socket.AF_INET6 (IPv6), socket.AF_UNIX (Unix-доменные сокеты для межпроцессного взаимодействия на одной машине).
  • type (тип сокета): определяет тип коммуникации. socket.SOCK_STREAM (потоковый сокет, TCP, обеспечивает надежное соединение), socket.SOCK_DGRAM (дейтаграммный сокет, UDP, без установки соединения), socket.SOCK_RAW (сырой сокет для низкоуровневых операций).
  • proto (протокол): номер протокола. Обычно равен 0, что означает выбор протокола по умолчанию для заданного семейства и типа (например, TCP для SOCK_STREAM).
  • fileno: необязательный файловый дескриптор существующего сокета. Если указан, остальные параметры игнорируются, а функция возвращает сокет, связанный с этим дескриптором.

Возвращаемое значение: объект сокета, который поддерживает методы для привязки (bind), прослушивания (listen), подключения (connect), отправки (send) и получения (recv) данных.

Простые примеры использования

Создание TCP-сокета для IPv4 (наиболее распространенный вариант):

import socket

# Создание TCP/IP сокета
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f'Сокет создан: {sock}')
# Закрытие сокета
sock.close()
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>

Создание UDP-сокета для IPv6:

import socket

# Создание UDP/IP сокета для IPv6
sock_udp = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
print(f'UDP IPv6 сокет: {sock_udp}')
sock_udp.close()
<socket.socket fd=3, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_DGRAM, proto=0>

Создание Unix-доменного потокового сокета:

import socket

sock_unix = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
print(f'Unix-сокет: {sock_unix}')
sock_unix.close()
<socket.socket fd=3, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>

Похожие возможности в Python

Модуль socket предлагает дополнительные функции для работы с сокетами:

  • socket.socketpair(): создает пару связанных сокетов, полезную для межпроцессного взаимодействия (IPC) в рамках одного хоста.
  • socket.create_connection(address): высокоуровневая функция для установки TCP-соединения с указанным адресом, автоматически разрешающая доменные имена и обрабатывающая таймауты.
  • socket.create_server(address) (Python 3.8+): удобная функция для создания TCP-сервера с привязкой к адресу и переходом в режим прослушивания.
  • Модули высшего уровня: Для типичных задач часто предпочтительнее использовать библиотеки, построенные на сокетах: http.server для HTTP, socketserver для упрощения создания сетевых серверов, asyncio для асинхронного программирования, фреймворки типа Flask или Django для веб-разработки.

Функцию socket.socket() выбирают, когда необходим полный контроль над сетевым взаимодействием или при реализации нестандартных протоколов.

Аналоги функции в других языках

PHP: Функция socket_create имеет схожую семантику.

// Создание TCP сокета
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
var_dump($socket);
resource(4) of type (Socket)

JavaScript (Node.js): Модуль net для TCP и dgram для UDP.

const net = require('net');
// Создание TCP сокета
const socket = new net.Socket();
console.log(socket);
Socket { ... }

Java: Класс java.net.Socket для клиента и java.net.ServerSocket для сервера.

import java.net.Socket;

Socket socket = new Socket();
System.out.println(socket);
Socket[unconnected]

C#: Класс System.Net.Sockets.Socket.

using System.Net.Sockets;

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(socket);
System.Net.Sockets.Socket

Golang: Пакет net, функции net.Dial для клиента и net.Listen для сервера.

package main
import "net"

conn, _ := net.Dial("tcp", "golang.org:80")
println(conn)
&{0xc00011a000}

Отличия от Python часто заключаются в объектно-ориентированном дизайне (Java, C#) или более высокой уровне абстракции (Golang, Node.js).

Распространенные ошибки

Address already in use: Попытка привязать сокет к порту, который уже занят другим процессом.

import socket
import time

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('127.0.0.1', 8080))
s1.listen(1)

s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    s2.bind(('127.0.0.1', 8080))
except OSError as e:
    print(f'Ошибка: {e}')

s1.close()
s2.close()
Ошибка: [Errno 98] Address already in use

Connection refused: Клиент пытается подключиться к порту, на котором нет слушающего сервера.

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    client.connect(('127.0.0.1', 9999)) # Предполагаем, что порт свободен
except ConnectionRefusedError as e:
    print(f'Ошибка подключения: {e}')

client.close()
Ошибка подключения: [Errno 111] Connection refused

Blocking operation timed out: Операция (например, recv) превысила установленный таймаут.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.5) # Таймаут 0.5 секунды
try:
    # Попытка принять данные, которых нет
    data = s.recv(1024)
except socket.timeout:
    print('Истекло время ожидания данных')

s.close()
Истекло время ожидания данных

Изменения в последних версиях Python

  • Python 3.8: Добавлена константа socket.AF_CAN для работы с Controller Area Network (CAN). Добавлен флаг socket.SOCK_NONBLOCK для Linux/BSD, упрощающий создание неблокирующих сокетов при использовании с type (например, socket.SOCK_STREAM | socket.SOCK_NONBLOCK).
  • Python 3.9: Добавлены константы для адресов IPv4-mapped IPv6 (socket.IPPROTO_IPV6, socket.IPV6_V6ONLY).
  • Python 3.10: Улучшена поддержка перечисления IntEnum для семейств адресов и типов сокетов, что упрощает их отладку и использование.
  • Python 3.11: Внесены внутренние оптимизации, влияющие на производительность операций с сокетами. Добавлена функция socket.sethostname() (доступна только на Unix, требует привилегий).

Общее направление изменений - добавление поддержки новых протоколов и системных вызовов, а также улучшение удобства использования и производительности.

Расширенные примеры применения

Создание неблокирующего сокета (Linux/BSD):

Пример python
import socket
import sys

if sys.platform.startswith('linux'):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM | socket.SOCK_NONBLOCK)
    print('Неблокирующий сокет создан:', sock.getblocking())
else:
    print('Платформа не поддерживает SOCK_NONBLOCK')
# Альтернативный способ на всех платформах
sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock2.setblocking(False)
print('Сокет setblocking(False):', sock2.getblocking())
Неблокирующий сокет создан: False
Сокет setblocking(False): False

Использование сырого сокета для отправки кастомного ICMP-пакета (требует прав администратора/root):

Пример python
import socket
import struct
import os

# Только для демонстрации структуры
if os.name == 'posix' and os.geteuid() == 0:
    try:
        # Создание сырого сокета для ICMP (протокол 1)
        sock_raw = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
        # Создание простого ICMP echo-запроса (тип 8, код 0)
        header = struct.pack('bbHHh', 8, 0, 0, 1, 1)
        sock_raw.sendto(header, ('8.8.8.8', 0))
        print('Сырой ICMP-пакет отправлен')
    except PermissionError:
        print('Недостаточно прав для создания сырого сокета')
    finally:
        if 'sock_raw' in locals():
            sock_raw.close()
else:
    print('Пример требует прав администратора (root) на Unix-системах')
Пример требует прав администратора (root) на Unix-системах

Создание сокета из существующего файлового дескриптора (например, переданного от родительского процесса):

Пример python
import socket
import os

# Создаем обычный сокет и получаем его файловый дескриптор
sock_orig = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
fd = sock_orig.fileno()
print('Исходный файловый дескриптор:', fd)

# Создаем новый объект сокета из дескриптора
sock_from_fd = socket.socket(fileno=fd)
print('Сокет из дескриптора:', sock_from_fd)

# Закрываем один из объектов - оба ссылаются на один ресурс
sock_orig.close()
print('Сокет из fd всё еще открыт?', not sock_from_fd._closed)
sock_from_fd.close()
Исходный файловый дескриптор: 3
Сокет из дескриптора: <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>
Сокет из fd всё еще открыт? True

питон socket function comments

En
Socket Create a new socket