Введение в сетевое программирование. Сокеты.¶
Сокет — это программный интерфейс для обеспечения информационного обмена между процессами.
- Серверный — сокет, который принимает сообщения.
- Клиентский — сокет, который отправляет сообщения.
- Потоковые (на основе TCP, в коде обозначаются SOCK_STREAM ) — сокеты с установленным соединением на основе протокола TCP, передают поток байтов, который может быть двунаправленным — т.е. приложение может и получать и отправлять данные.
- Дейтаграммные (на основе UDP, в коде обозначаются SOCK_DGRAM ) — сокеты, не требующие установления явного соединения между ними. Сообщение отправляется указанному сокету и, соответственно, может получаться от указанного сокета.
Сокет состоит из IP-адреса и порта.
IP-адрес — уникальный сетевой адрес узла в компьютерной сети, построенной по протоколу IP. В версии протокола IPv4 IP-адрес имеет длину 4 байта (например, 192.168.0.3), а в версии протокола IPv6 IP-адрес имеет длину 16 байт (например, 2001:0db8:85a3:0000:0000:8a2e:0370:7334). IP-адрес должен быть уникален.
Порт — натуральное число, записываемое в заголовках протоколов транспортного уровня (TCP, UDP и др.). Порт используется для определения процесса-получателя пакета в пределах одного хоста.
В python для работы с сокетами используется встроенная библиотека socket . Одной из основных функций модуля является функция socket() , которая возвращает объект типа сокет, обладающий соответствующими функциями для работы с соединением.:
class socket.socket sock = socket.socket()
- socket.bind(address) — Привязывает сокет к адресу address (инициализирует IP-адрес и порт). Сокет не должен быть привязан до этого.
- socket.listen([backlog]) — Переводит сервер в режим приема соединений. Параметр«backlog (int)« – количество соединений, которые будет принимать сервер.
- socket.accept() — Принимает соединение и блокирует приложение в ожидании сообщения от клиента. В результате возвращает кортеж:
- conn : объект соединения (сокет), который можно использовать для отправки/получения данных;
- address : адрес клиента.
Работа с сокетом во многом схожа с работой с файловым объектом. Принцип — открыли соединение — считали данные — закрыли соединение.
Создание серверного сокета: .. code
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # создаем сокет sock.bind(('', 55000)) # связываем сокет с портом, где он будет ожидать сообщения sock.listen(10) # указываем сколько может сокет принимать соединений print('Server is running, please, press ctrl+c to stop') while True: conn, addr = sock.accept() # начинаем принимать соединения print('connected:', addr) # выводим информацию о подключении data = conn.recv(1024) # принимаем данные от клиента, по 1024 байт print(str(data)) conn.send(data.upper()) # в ответ клиенту отправляем сообщение в верхнем регистре conn.close() # закрываем соединение
Создание клиентского сокета: .. code
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # создаем сокет sock.connect(('localhost', 55000)) # подключемся к серверному сокету sock.send(bytes('Hello, world', encoding = 'UTF-8')) # отправляем сообщение data = sock.recv(1024) # читаем ответ от серверного сокета sock.close() # закрываем соединение print(data)
Обратите внимание, клиент отправляет байтовую строку, а не обычную. Сервер так же принимает в качестве сообщения байтовую строку и должен в ответе вернуть объект того же типа.
Задания¶
- Реализовать чат без графического интерфейса, который позволит обмениваться сообщениями только между клиентом и сервером. Клиент должен получать сообщения сервера в том числе.
- С помощью модуля easygui (см. полезные ссылки), добавьте в разработанный чат простой графический интерфейс.
- Разработайте приложение, которое будет запрашивать у пользователя название файла, а затем отправлять содержимое этого файла серверу. Сервер будет подсчитывать количество слов и возвращать ответ.
- Добавьте к чату из задачи 2 чат-бота на стороне сервера. Добавьте 4-5 фраз, которые сервер будет отправлять по определённым условиям.
Полезные ссылки:¶
- Easygui
- Файловый ввод-вывод
- Работа с файлами в Python
© Copyright Revision 07b34d26 .
Built with Sphinx using a theme provided by Read the Docs.
Read the Docs v: latestVersions latest Downloads html On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.
Сокеты в Python для начинающих
В далеком для меня 2010 году я писал статью для начинающих про сокеты в Python. Сейчас этот блог канул в небытие, но статья мне показалась довольно полезной. Статью нашел на флешке в либровском документе, так что это не кросспост, не копипаст — в интернете ее нигде нет.
Что это
Для начала нужно разобраться что такое вообще сокеты и зачем они нам нужны. Как говорит вики, сокет — это программный интерфейс для обеспечения информационного обмена между процессами. Но гораздо важнее не зазубрить определение, а понять суть. Поэтому я тут постараюсь рассказать все как можно подробнее и проще.
Существуют клиентские и серверные сокеты. Вполне легко догадаться что к чему. Серверный сокет прослушивает определенный порт, а клиентский подключается к серверу. После того, как было установлено соединение начинается обмен данными.
Рассмотрим это на простом примере. Представим себе большой зал с множеством небольших окошек, за которыми стоят девушки. Есть и пустые окна, за которыми никого нет. Те самые окна — это порты. Там, где стоит девушка — это открытый порт, за которым стоит какое-то приложение, которое его прослушивает. То есть, если, вы подойдете к окошку с номером 9090, то вас поприветствуют и спросят, чем могут помочь. Так же и с сокетами. Создается приложение, которое прослушивает свой порт. Когда клиент устанавливает соединение с сервером на этом порту именно данное приложение будет ответственно за работу этим клиентом. Вы же не подойдете к одному окошку, а кричать вам будут из соседнего 🙂
После успешной установки соединения сервер и клиент начинают обмениваться информацией. Например, сервер посылает приветствие и предложение ввести какую-либо команду. Клиент в свою очередь вводит команду, сервер ее анализирует, выполняет необходимые операции и отдает клиенту результат.
Сервер
Сейчас создайте два файла — один для сервера, а другой для клиента.
В Python для работы с сокетами используется модуль socket:
import socket
Прежде всего нам необходимо создать сокет:
sock = socket.socket()
Здесь ничего особенного нет и данная часть является общей и для клиентских и для серверных сокетов. Дальше мы будем писать код для сервера. Это вполне логично — зачем нам писать клиентское приложение, если некуда подключаться 🙂
Теперь нам нужно определиться с хостом и портом для нашего сервера. Насчет хоста — мы оставим строку пустой, чтобы наш сервер был доступен для всех интерфейсов. А порт возьмем любой от нуля до 65535. Следует отметить, что в большинстве операционных систем прослушивание портов с номерами 0 — 1023 требует особых привилегий. Я выбрал порт 9090. Теперь свяжем наш сокет с данными хостом и портом с помощью метода bind, которому передается кортеж, первый элемент (или нулевой, если считать от нуля) которого — хост, а второй — порт:
sock.bind(('', 9090))
Теперь у нас все готово, чтобы принимать соединения. С помощью метода listen мы запустим для данного сокета режим прослушивания. Метод принимает один аргумент — максимальное количество подключений в очереди. Напряжем нашу бурную фантазию и вспомним про зал с окошками. Так вот этот параметр определяет размер очереди. Если он установлен в единицу, а кто-то, явно лишний, пытается еще подстроится сзади, то его пошлют 🙂 Установим его в единицу:
sock.listen(1)
Ну вот, наконец-то, мы можем принять подключение с помощью метода accept, который возвращает кортеж с двумя элементами: новый сокет и адрес клиента. Именно этот сокет и будет использоваться для приема и посылке клиенту данных.
conn, addr = sock.accept()
Вот и все. Теперь мы установили с клиентом связь и можем с ним «общаться». Т.к. мы не можем точно знать, что и в каких объемах клиент нам пошлет, то мы будем получать данные от него небольшими порциями. Чтобы получить данные нужно воспользоваться методом recv, который в качестве аргумента принимает количество байт для чтения. Мы будем читать порциями по 1024 байт (или 1 кб):
while True: data = conn.recv(1024) if not data: break conn.send(data.upper())
Как мы и говорили для общения с клиентом мы используем сокет, который получили в результате выполнения метода accept. Мы в бесконечном цикле принимаем 1024 байт данных с помощью метода recv. Если данных больше нет, то этот метод ничего не возвращает. Таким образом мы можем получать от клиента любое количество данных.
Дальше в нашем примере для наглядности мы что-то сделаем с полученными данными и отправим их обратно клиенту. Например, с помощью метода upper у строк вернем клиенту строку в верхнем регистре.
Теперь можно и закрыть соединение:
conn.close()
Собственно сервер готов. Он принимает соединение, принимает от клиента данные, возвращает их в виде строки в верхнем регистре и закрывает соединение. Все просто 🙂 В итоге у вас должно было получиться следующее:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket sock = socket.socket() sock.bind(('', 9090)) sock.listen(1) conn, addr = sock.accept() print 'connected:', addr while True: data = conn.recv(1024) if not data: break conn.send(data.upper()) conn.close()
Клиент
Думаю, что теперь будет легче. Да и само клиентское приложение проще — нам нужно создать сокет, подключиться к серверу послать ему данные, принять данные и закрыть соединение. Все это делается так:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket sock = socket.socket() sock.connect(('localhost', 9090)) sock.send('hello, world!') data = sock.recv(1024) sock.close() print data
Думаю, что все понятно, т.к. все уже разбиралось ранее. Единственное новое здесь — это метод connect, с помощью которого мы подключаемся к серверу. Дальше мы читаем 1024 байт данных и закрываем сокет.
- Python
- Программирование
библиотека для TCP/IP сокет подключений
Собственно, порекомендуйте, пожалуйста, библиотеку для TCP/IP сокет.
А, да, условие: поддержка GNU/Linux, MS Windows
sniper21 ★★★★★
15.01.18 19:41:44 MSKнапиши еще свой язык программирования, потому что это главный фактор
dave★★★★★
( 15.01.18 19:52:49 MSK )
Harald ★★★★★
( 15.01.18 19:58:22 MSK )
Ответ на: комментарий от Harald 15.01.18 19:58:22 MSKмногие дистрибутивы гнулинукса рекомендуют
Harald ★★★★★
( 15.01.18 19:58:38 MSK )
hippi90 ★★★★★
( 15.01.18 19:59:35 MSK )Тебе для прожки? А почему не указал язык программирования?
I-Love-Microsoft ★★★★★
( 15.01.18 20:38:10 MSK )
Ответ на: комментарий от I-Love-Microsoft 15.01.18 20:38:10 MSK
sniper21 ★★★★★
( 15.01.18 21:40:46 MSK ) автор топика
anonymous
( 15.01.18 21:45:13 MSK )
Ответ на: комментарий от anonymous 15.01.18 21:45:13 MSKдык не поддерживается 🙁
sniper21 ★★★★★
( 15.01.18 21:46:29 MSK ) автор топика
Ответ на: комментарий от sniper21 15.01.18 21:46:29 MSKЧем не поддерживается?
BRE ★★
( 15.01.18 21:52:02 MSK )
Ответ на: комментарий от BRE 15.01.18 21:52:02 MSK
sniper21 ★★★★★
( 15.01.18 21:57:46 MSK ) автор топика
Ответ на: комментарий от sniper21 15.01.18 21:57:46 MSKА если asio в boost поискать? 🙂
BRE ★★
( 15.01.18 22:00:03 MSK )
Ответ на: комментарий от BRE 15.01.18 22:00:03 MSKА Boost жирно для мелкопроекта. cURL’ом значит, только cURL’ом.
sniper21 ★★★★★
( 15.01.18 22:13:45 MSK ) автор топика
Ответ на: комментарий от BRE 15.01.18 22:00:03 MSKа зачем его там искать ?
dhampire ★★★
( 15.01.18 22:49:34 MSK )
Ответ на: комментарий от sniper21 15.01.18 21:57:46 MSK
dhampire ★★★
( 15.01.18 22:51:42 MSK )Qt, boost asio, poco.
rumgot ★★★★★
( 15.01.18 22:57:12 MSK )
Ответ на: комментарий от dhampire 15.01.18 22:49:34 MSKА почему вы спрашиваете?
anonymous
( 15.01.18 22:57:52 MSK )
Ответ на: комментарий от sniper21 15.01.18 22:13:45 MSKПочему жирно? Ты ведь используешь только те части буста, которые тебе требуются.
rumgot ★★★★★
( 15.01.18 22:58:18 MSK )
Ответ на: комментарий от dhampire 15.01.18 22:49:34 MSKЗатем, что кроме asio из буста удобно использовать и некоторые другие его библиотеки. А использовать boost и отдельный asio как-то избыточно.
BRE ★★
( 16.01.18 01:59:26 MSK )
Ответ на: комментарий от sniper21 15.01.18 22:13:45 MSKЕсли не ошибаюсь, то в случае использования boost asio нужно будет доложить в дистрибутив твоей программы примерно три либы, но уже смутно помню, какие
Посмотри еще библиотеку libev, но все зависит от того способа, как ты обрабатываешь соединения
dave★★★★★
( 16.01.18 07:47:01 MSK )Укажи хотя бы зачем тебе оно. Просто инфу по http тягать, или какой-то свой протокол обмена реализовывать.
Библиотека Socket.IO: что это такое и как с ней работать
Socket.IO — это библиотека JavaScript(Node.js), обеспечивающая двустороннюю связь между клиентами и серверами в режиме реального времени, которая построена на основе протокола WebSocket. Более подробно об этом протоколе читайте в нашей статье «Что такое веб-сокеты и как они вообще работают».
Базовая концепция работы Socket.IO
Базовая концепция, которую нам нужно понять при использовании Socket.io , основана на событиях, где:
- Одна из сторон (сервер или клиент) инициирует событие
- Другая сторона реагирует на это событие
Сервер
socket.emit('hello');
Клиент
socket.on('hello', () => console.log('hello world!'); >);
Когда сервер инициирует событие hello , то его получит объект сокета на клиенте и отреагирует с помощью переданного в это событие колбека. В данном случае в консоль будет выведено сообщение сообщение hello world! .
Несколько событий и обработчиков
Мы можем создавать столько событий, сколько захотим. Кроме того, мы можем ловить их и реагировать на них по-разному.
Сервер
socket.emit('goodbye');
Клиент
socket.on('hello', () => console.log('hello world!'); >); socket.on('goodbye', () => console.log('goodbye world!'); >);
В этом случае мы запускаем событие goodbye на нашем сервере, поэтому клиент поймает это событие и напечатает goodbye world! в консоли на клиенте.
Отправка данных в рамках событий
Иногда мы хотим не только запустить событие, но и отправить некоторую информацию клиенту. Для этого можно просто добавить объекты, которые мы хотим отправить, в качестве параметров для эмита, а потом получить их в нашей функции обратного вызова.
Сервер
const person = name: 'Rene', age: 26>; socket.emit('person', person);
Клиент
socket.on('person', (person) => console.log(`$person.name> is $person.age> years old`); >);
Двусторонняя связь
Socket.io позволяет использовать двустороннюю связь — то есть мы можем не только отправлять информацию с сервера на клиент, но и наоборот, отправлять с клиента на сервер.
Сервер
const person = name: 'Rene', age: 26>; socket.emit('person', person); socket.on('confirmation', () => console.log('The client received the person'); >);
Клиент
socket.on('person', (person) => console.log(`$person.name> is $person.age> years old`); socket.emit('confirmation'); >);
После того, как клиент получит данные, мы отправим событие confirmation внутри колбека, чтобы сообщить серверу, что клиент получил данные. То есть, мы можем генерировать события внутри обратных вызовов для других событий.
Создание соединения Socket.IO
На стороне сервера
Теперь, когда мы понимаем, как генерировать события, отправлять в них данные и реагировать на них, пришло время создать сокет между клиентом и сервером. На стороне нашего сервера (Node.js) нужно установить Socket.io с помощью менеджера пакетов пакетов npm:
install socket.io
Как только мы создали объект Socket.io и подключили его к http-серверу, нам нужно обрабатывать клиентские подключения. При клиентском соединении сервер будет генерировать событие connection . Это событие соединения может быть обработано объектом io для создания сокета.
const app = require('http').createServer(handler); const io = require('socket.io')(app); app.listen(80); io.on('connection', (socket) => // здесь будет код >);
Каждый объект сокета представляет собой коммуникационный тоннель между клиентом и сервером. Поэтому каждый раз, когда клиент подключается к серверу, будет создаваться новый коммуникационный тоннель.
На стороне клиента
На стороне клиента нам также нужно установить Socket.io через npm:
install socket.io-client
src="https://cdn.socket.io/4.6.0/socket.io.min.js">
Как только мы это сделаем, можно будет создать новый сокет, подключившись к нашему собственному http-серверу с помощью объекта io (клиент):
const socket = io('http://localhost'); // далее используем socket
Соединяем все вместе
Теперь, когда у нас есть сокет и на сервере, и на клиенте, мы можем начать генерировать события, как делали это раньше.
Сервер
const app = require('http').createServer(); const io = require('socket.io')(app); app.listen(80); io.on('connection', (socket) => socket.on('message', (message) => console.log(message); >); socket.emit('message','Hello, my name is Server'); >);
Клиент
const socket = io(''); socket.on('message', (message) => console.log(message); >); socket.emit('message','Hello, my name is Client');
Вот и все! Мы успешно создали соединение Socket.io .
Эта статья — адаптированный перевод материала Quick guide to Socket.io basics , опубликованного в блоге сервиса Medium. Мнение редакции Хекслета может не совпадать с мнением автора.
Продолжайте учиться: На Хекслете есть несколько больших профессий, интенсивов и треков для джуниоров, мидлов и даже сеньоров: они позволят не только узнать новые технологии, но и прокачать уже существующие навыки