Рубрики
Без рубрики

Базовое программирование сокетов на Python

Автор оригинала: Frank Hofmann.

В целом сетевые службы следуют традиционной модели клиент-сервер. Один компьютер действует как сервер для предоставления определенной услуги, а другой компьютер представляет клиентскую сторону, которая использует эту услугу. Для связи по сети в игру вступает сетевой сокет , в основном называемый только сокетом. Этот вид связи сокетов может даже использоваться внутренне в компьютере для межпроцессной связи (IPC).

В этой статье объясняется, как написать простое клиент-серверное приложение, которое взаимодействует через сетевой сокет с использованием языка программирования Python. Для простоты наш примерный сервер выводит только полученные данные в stdout. Идея клиент-серверного приложения-это датчик на метеостанции, который собирает данные о температуре с течением времени и отправляет собранные данные в серверное приложение, где данные обрабатываются дальше.

Что такое розетка?

Сетевой сокет-это конечная точка двусторонней линии связи между двумя программами или процессами – в нашем случае клиентом и сервером, – которые работают в сети. Это может быть как на одном компьютере, так и на разных системах, подключенных через сеть.

Обе стороны взаимодействуют друг с другом путем записи или чтения из сетевого сокета. Технический эквивалент в реальности-это телефонная связь между двумя участниками. Сетевая розетка представляет собой соответствующий номер телефонной линии или договор в случае сотовых телефонов.

Пример

Для того чтобы использовать функциональность сокета, необходим только модуль Python socket . В приведенном ниже примере кода Python time module также импортируется для имитации метеостанции и упрощения расчетов времени.

В этом случае и клиент, и сервер работают на одном компьютере. Сокет имеет соответствующий номер порта, который в нашем случае равен 23456. При желании вы можете выбрать другой номер порта из неограниченного диапазона номеров от 1024 до 65535.

Сервер

Загрузив дополнительный модуль Python socket , с помощью сокета создается сокет потоковой передачи Интернета.socket класс с двумя параметрами socket.AF_INET и сокет.SOCK_STREAM . Поиск имени хоста, полного доменного имени и IP-адреса осуществляется методами gethostname () , getfqdn () и gethostbyname () соответственно. Далее сокет привязывается к IP-адресу и номеру порта 23456 с помощью метода bind () .

С помощью метода listen() сервер прослушивает входящие соединения на указанном порту. В цикле while сервер ожидает входящих запросов и принимает их с помощью метода accept () . Данные, представленные клиентом, считываются с помощью метода recv() в виде фрагментов по 64 байта и просто выводятся в stdout. Наконец, текущее соединение закрывается, если никакие дополнительные данные не отправляются от клиента.

# load additional Python module
import socket

# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# retrieve local hostname
local_hostname = socket.gethostname()

# get fully qualified hostname
local_fqdn = socket.getfqdn()

# get the according IP address
ip_address = socket.gethostbyname(local_hostname)

# output hostname, domain name and IP address
print ("working on %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))

# bind the socket to the port 23456
server_address = (ip_address, 23456)
print ('starting up on %s port %s' % server_address)
sock.bind(server_address)

# listen for incoming connections (server mode) with one connection at a time
sock.listen(1)

while True:
    # wait for a connection
    print ('waiting for a connection')
    connection, client_address = sock.accept()

    try:
        # show who connected to us
        print ('connection from', client_address)

        # receive the data in small chunks and print it
        while True:
            data = connection.recv(64)
            if data:
                # output received data
                print ("Data: %s" % data)
            else:
                # no more data -- quit the loop
                print ("no more data.")
                break
    finally:
        # Clean up the connection
        connection.close()

клиент

Теперь посмотрим на клиентскую сторону. Код Python в основном похож на серверную сторону, за исключением использования сокета – вместо этого клиент использует метод connect () . В цикле for данные о температуре отправляются на сервер с помощью метода sendall () . Вызов метода time.sleep(2) приостанавливает работу клиента на две секунды, прежде чем он отправит еще одно показание температуры. После отправки всех данных о температуре из списка соединение окончательно закрывается с помощью метода close () .

# load additional Python modules
import socket
import time

# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# retrieve local hostname
local_hostname = socket.gethostname()

# get fully qualified hostname
local_fqdn = socket.getfqdn()

# get the according IP address
ip_address = socket.gethostbyname(local_hostname)

# bind the socket to the port 23456, and connect
server_address = (ip_address, 23456)
sock.connect(server_address)
print ("connecting to %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))

# define example data to be sent to the server
temperature_data = ["15", "22", "21", "26", "25", "19"]
for entry in temperature_data:
    print ("data: %s" % entry)
    new_data = str("temperature: %s\n" % entry).encode("utf-8")
    sock.sendall(new_data)
    
    # wait for two seconds
    time.sleep(2)

# close connection
sock.close()

Запуск сервера и клиента

Чтобы запустить как серверную, так и клиентскую программу, откройте два окна терминала и выполните следующие команды – по одной на каждое окно терминала и в следующем порядке:

$ python3 echo-server.py

и

$ python3 echo-client.py

На двух рисунках ниже показаны соответствующие выходные данные примера программы:

Связь серверных сокетов в Python
Связь клиентских сокетов в Python

Вывод

Написание программ на Python, использующих IPC с сокетами, довольно просто. Приведенный выше пример, безусловно, может быть расширен, чтобы справиться с чем-то более сложным. Для получения дополнительной информации и дополнительных методов вы можете ознакомиться с некоторыми замечательными ресурсами программирования сокетов Python.