Сокеты в Python
Сегодня мы рассмотрим пример программирования сокетов Python. Мы создадим серверные и клиентские приложения на Python.
Программирование сокетов
Чтобы понять программирование сокетов Python, нам нужно знать о трех интересных темах – Socket Server, Socket Client и Socket.
Итак, что такое сервер? Сервер – это программное обеспечение, которое ожидает запросов клиентов и обслуживает или обрабатывает их соответственно.
С другой стороны, клиент запрашивает эту услугу. Клиентская программа запрашивает некоторые ресурсы к серверу, и сервер отвечает на этот запрос.
Socket – это конечная точка двунаправленного канала связи между сервером и клиентом. Сокеты могут обмениваться данными внутри процесса, между процессами на одной машине или между процессами на разных машинах. Для любого взаимодействия с удаленной программой мы должны подключаться через порт сокета.
Основная цель этого руководства по программированию сокетов – познакомить вас с тем, как сервер сокетов и клиент взаимодействуют друг с другом. Вы также узнаете, как написать программу сервера сокетов в Python.
Пример
Ранее мы говорили, что клиент сокета запрашивает некоторые ресурсы у сервера, и сервер отвечает на этот запрос.
Итак, мы разработаем и серверную, и клиентскую модель, чтобы каждый мог общаться с ними. Шаги можно рассматривать так:
- Программа сервера сокетов запускается сначала и ждет любого запроса.
- Клиентская программа сначала инициирует диалог.
- Затем серверная программа будет реагировать на запросы клиента соответственно.
- Клиентская программа будет завершена, если пользователь введет сообщение «до свидания». Серверная программа также завершится, когда завершится клиентская программа, это необязательно, и мы можем поддерживать выполнение серверной программы на неопределенный срок или завершить работу с помощью какой-либо конкретной команды в клиентском запросе.
Сервер сокетов
Мы сохраним программу сервера сокетов, как socket_server.py. Чтобы использовать соединение, нам нужно импортировать модуль сокета.
Затем последовательно нам нужно выполнить некоторую задачу, чтобы установить соединение между сервером и клиентом.
Мы можем получить адрес хоста с помощью функции socket.gethostname(). Рекомендуется использовать адрес порта пользователя выше 1024, поскольку номер порта меньше 1024 зарезервирован для стандартного интернет-протокола.
Смотрите приведенный ниже пример кода сервера:
import socket def server_program(): # get the hostname host = socket.gethostname() port = 5000 # initiate port no above 1024 server_socket = socket.socket() # get instance # look closely. The bind() function takes tuple as argument server_socket.bind((host, port)) # bind host address and port together # configure how many client the server can listen simultaneously server_socket.listen(2) conn, address = server_socket.accept() # accept new connection print("Connection from: " + str(address)) while True: # receive data stream. it won't accept data packet greater than 1024 bytes data = conn.recv(1024).decode() if not data: # if data is not received break break print("from connected user: " + str(data)) data = input(' -> ') conn.send(data.encode()) # send data to the client conn.close() # close the connection if __name__ == '__main__': server_program()
Итак, наш сервер сокетов работает на порту 5000 и будет ждать запроса клиента. Если вы хотите, чтобы сервер не завершал работу при закрытии клиентского соединения, просто удалите условие if и оператор break. Цикл while используется для бесконечного запуска серверной программы и ожидания клиентского запроса.
Клиент сокета
Мы сохраним клиентскую программу сокета python как socket_client.py. Эта программа похожа на серверную, за исключением привязки.
Основное различие между серверной и клиентской программой состоит в том, что в серверной программе необходимо связать адрес хоста и адрес порта вместе.
Смотрите ниже пример кода клиента сокета:
import socket def client_program(): host = socket.gethostname() # as both code is running on same pc port = 5000 # socket server port number client_socket = socket.socket() # instantiate client_socket.connect((host, port)) # connect to the server message = input(" -> ") # take input while message.lower().strip() != 'bye': client_socket.send(message.encode()) # send message data = client_socket.recv(1024).decode() # receive response print('Received from server: ' + data) # show in terminal message = input(" -> ") # again take input client_socket.close() # close the connection if __name__ == '__main__': client_program()
Вывод
Чтобы увидеть результат, сначала запустите программу сервера сокетов. Затем запустите клиентскую программу. После этого напишите что-нибудь из клиентской программы. Затем снова напишите ответ от серверной программы.
Наконец, напишите «до свидания» из клиентской программы, чтобы завершить обе программы. Ниже короткое видео покажет, как это работало на моем тестовом прогоне примеров программ сервера сокетов и клиента.
pankaj$ python3.6 socket_server.py Connection from: ('127.0.0.1', 57822) from connected user: Hi -> Hello from connected user: How are you? -> Good from connected user: Awesome! -> Ok then, bye! pankaj$
pankaj$ python3.6 socket_client.py -> Hi Received from server: Hello -> How are you? Received from server: Good -> Awesome! Received from server: Ok then, bye! -> Bye pankaj$
Обратите внимание, что сервер сокетов работает на порту 5000, но клиенту также требуется порт сокета для подключения к серверу. Этот порт назначается случайным образом при вызове клиентского соединения. В данном случае это 57822.
Создание клиент-сервер на Python для зародышей
Приветик. В данной статье не будет никакой занудной теории по типу «А чТо ТаКоЕ СЕРВЕР. «. Мы будем вкратце описывать работу клиент-сервер, а также приведём примеры. Данная статья будет интересна тем, кто не до конца понимает как работает клиент-сервер, кто забивает в череп гвозди, чтобы повысить содержание железа и стать умнее, кто думает что клиент-сервер это что-то заоблачное для обычного начинающего кодера.
Итак, приступим к описанию принципов работы:
- Сервер, на IP адресе по порту ожидает подключения на указанный IP адрес с портом . IP машины и IP приёма должны быть одинаковы. Порты имеют значения в диапазоне 0-65535.
- Далее, клиент хочет зайти на ваш сервер. Изначально, наш сервер это небольшая консоль для доступа . например к дневнику Иванова Ивана и 5Б. Клиент вводит IP и порт , после чего по TCP или UPD происходит обмен данными.
- Сервер видит что кто-то хочет посмотреть нюдсы Иванова Ивана и просто отсылает их обратно клиенту.
— Вот так мы максимально кратко расписали клиент-сервер. Распишем немного побольше.
— ЭЙ СТОЙ! А чо ещё за TCP и UPD?
— Секундочку.
Что такое UPD и TCP?
Вкратце это технологии передачи данных между двумя устройствами. Они оба разные как лолихантер и милфхантер. Приведём парочку примеров:
— Эй, Санёк, я тут камни нашёл. Можно я в тебя его кину?
— Хорошо, Шанёк, кидай
— Разрешение кидать получено!
*Кинул камни настолько мягко и последовательно, что Санёк успел словить все*
Это был пример работы TCP. Он превосходит UPD в целостности данных, строго последовательным отправлением данных и большей надёжности, но в отличии от него меньшей скоростью.
— Эй, Санёк, лови!
*Кинул камни так сильно, что Санёк сразу дал дёру, успев сначала словить большую часть камней*
— *****, не поймал, в лицо попал
Это был пример работы UPD. В отличии от своего «прилежного» брата он более быстрый в закидывании камня. Но вместо строгой последовательности отправки данных, кидает всё что видит.
Теперь черпанём немного практики.
Для начала сделаем вечно получающий информацию сервер.
Для передачи информации через сокеты в Python используем socket
Теперь же нам надо сделать слушалку.
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) IP = socket.gethostbyname(socket.gethostname()) PORT = 12333 listener.bind((IP, PORT)) listener.listen(0) connection, address = listener.accept()
socket.socket() — создаём наш сокет. Тут мы просто создаём коробку определённого вида, цвета, размера (повторяю, это формально). Но без содержимого.
socket.setsockopt() — добавляем в нашу коробку пенопласт для информации. Настраиваем опции коробки: какой пенопласт, размеры и т.д.
IP = socket.gethostbyname(socket.gethostname()) — получаем наш IP. В функцию передаётся имя ПК, IP которого мы хотим получить, в нашем случае нас.
listener.bind((IP, PORT)) — устанавливаем данные для прослушивания данного порта. Берём почтовый ящик IP/PORT. Данные передаются кортежем, это не ошибка!
listener.listen() — разрешаем серверу принимать запросы.
listener.accept() — в случае найденного пользователя разрешаем ему подключиться
Теперь у нас есть почтовый ящик и заранее готовая коробка с посылкой. Теперь нам нужно проверять наш почтовый ящик. Наш почтовый ящик вмещает 1 КБ (1024 байт). Поэтому нам нужно каждый раз открывать ящик, забирать оттуда данные и продолжать до тех пор, пока ящик не опустеет.
connection.send("Привет, подкючайся!".encode('utf8')) connection.send("Привет!".encode('utf8')) while True: data_output = '' while True: data = connection.recv(1024).decode("utf8") data_output+=data if not data: break print(data_output)
connection.send() — отправить данные. Для вашей же живучести используйте .encode(«utf8»)
connection.recv(1024) — получить 1024 байт данных. Для вашей же живучести используйте .decode(«utf8»)
Вот так мы будем получать информацию о том, что нам отправили. Это как будто вы перевернули почтовый ящик вверх дном и высыпаете оттуда всё до конца.
— Но зачем в начале нам отправлять данные?
Таким образом мы показываем клиенту что готовы работать. Если бы мы этого не сделали, клиент бы стоял молчал.
Раз уж с сервером окончено перейдём к клиенту
import socket connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) IP = "айпи сервера" PORT = 12333 connection.connect((IP, PORT)) rd = connection.recv(1024) print(rd.decode('utf8')) connection.send("И тебе привет!".encode('utf8')) connection.close()
connection.connect() — начать подключение. Данные в функцию передаются кортежем!
connection.close() — закрыть соединение
Ну вот, теперь при запуске клиента по IP, от сервера мы получим «Привет», а сервер получит наше «И тебе привет!», а также продолжит ждать от нас ответ.
Прошу акцентировать внимание, что эти каналы легко прослушать, а по сему для передачи личных данных желательно пользоваться алгоритмами шифрования (например идеально подойдёт RSA).
Немного дополнительных вопросов:
- Можно ли при помощи сокетов сделать консоль? Как реализовать в нём команды?
- Конечно. Команды можно реализовать просто отправкой сообщения, а после получения обработкой через условия.
- Как сделать таймаут?
- Используйте на вашем подключении .settimeout(Время в секундах).
- Что если я укажу чужой адрес в прослушивании сервера?
- Вам просто выбьет ошибку.
- Можно ли по сокетам передавать фото, видео и т.д.?
- Да, конечно. Фото и видео это просто данные. Их можно прочесть, а соответственно и отправить.
Небольшая справочка по основным командам для создания сокетов:
socket.socket(socket.AF_INET, socket.SOCK_STREAM) — создать сокет
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) — настроить сокет
socket.gethostbyname(socket.gethostname()) — получить наш готовый IP
listener.bind((IP, PORT)) — прослушивать данный IP по порту. Данные передаются кортежем!
listener.listen(0) — разрешаем серверу принимать запросы
listener.accept() — принимаем запрос на передачу данных
connection.send() — отправить данные
connection.recv(1024) — получить данные. Значение в скобочках, количество байт которые можно принять за один раз
connection.settimeout() — установить таймаут соединения
connection.connect() — установить подключение к серверу
connection.close() — закрыть соединение
Дополнительные источники, полезные ссылки:
И на этом мы закончим вступление клиент-сервер в Python для зародышей. Напомню что данная статья не создана для Truehard кодеров, она создана для тех кто не разбирается в сокетах и хочет понять как с ними работать.