Автор оригинала: 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, использующих IPC с сокетами, довольно просто. Приведенный выше пример, безусловно, может быть расширен, чтобы справиться с чем-то более сложным. Для получения дополнительной информации и дополнительных методов вы можете ознакомиться с некоторыми замечательными ресурсами программирования сокетов Python.