Оглавление
1. Как доставить пакет программе
Данные между компьютерами пересылаются с помощью пакетов: последовательностей байт, которые содержат информацию об отправителе, цели, а также могут содержать пользовательские данные.
Заметьте, я называю пакет именно последовательностью байт. Это важно, многие современные библиотеки скрывают от пользователя тот факт, что он отправляет байты, утверждая, что он отправляет строку или число, а иногда и вовсе экземпляр класса. Часто вам придётся отправлять данные системе, написанной с помощью другой библиотеки, в таких ситуациях вам нужно точно знать, как именно интерпретировать полученные пакеты и как их составлять. Подробнее в следующей статье.
Из прошлой статьи вы узнали, что для того, чтобы доставить пакет конкретной машине требуется либо находится в одной подсети и знать её серый IP адрес, либо она должна иметь белый IP адрес.
В реальности этого недостаточно, на одном компьютере чаще всего запущено более одного процесса: система, различные фоновые процессы и, конечно же, нужный нам процесс. Для того, чтобы доставить нашу информацию конкретному процессу, были придуманы порты.
Порт - это число, которое должно однозначно определить какому процессу на машине предназначается полученная информация. Программа, которая ожидает данные, слушает порт, когда адаптер обнаруживает новые данные, система оповещает слушающий процесс и тот их обрабатывает. Также отправляя данные, программа использует какой-то порт.
В итоге, в общем случае схема передачи данных между двумя компьютерами выглядит примерно так:
Теперь поясню этот рисунок. Допустим, нужный процесс на компьютере 1 хочет отправить информацию процессу на компьютере 2. Для этого он отправит пакет через порт 4, указав целью IP адрес компьютера 2 и порт номер 2.
Аналогично, если процесс на 2 компьютере хочет отправить пакет процессу на 1 компьютере, то он отправит его с порта 3, указав целью IP адрес компьютера 1 и порт 2.
2. Сокеты
Сейчас, когда описана вся теория по пересылке данных, возникает вопрос: "Как с этим работать, если я программист?". Для удобной работы с портами и пересылкой данных используют сокеты.
С точки зрения программиста, сокет - это некий объект, который может отправлять данные и/или принимать их.
Сокет можно привязать к какому-то порту и адаптеру, тогда процесс заберёт у системы этот порт, после привязки только этот процесс и, как правило, только этот сокет сможет использовать указанный порт. Процесс в забравший себе порт получает возможность принимать сообщения, приходящие на него.
Обычно, одновременно только один сокет может быть привязан к одному порту.
Как правило, сокеты поддерживают следующие операции:
- send(данные, адрес) #Отправка данных
- данные = recv(размер хранилища) #Получение данных
- bind(адрес) #Привязка сокета к указанному порту
- close() #Закрывает сокет для подключений и отвязывает, если он был привязан
При этом существуют 2 режима работы сокетов:
- Блокирующий
- Неблокирующий
В блокирующем режиме, при вызове recv или другой операции ожидающий события, сокет будет бесконечно ожидать подключения. Если подключение так и не произойдёт, то программа просто зависнет. Но можно установить время ожидания, после которого сокет прервёт операцию и сообщит от ошибке. Иногда это определяют как отдельный режим работы сокета. В неблокирующем режиме сокет вернёт информацию об отсутствии пакета или сам пакет сразу при вызове recv.
3. Работа с множеством сокетов.
Из схемы выше видно, что даже для взаимодействия двух процессов может потребоваться более одного порта и, соответственно, более одного сокета. Использование неблокирующего режима может привести к потере пакетов. Для правильной работы вашего сервера требуются параллельные прослушивания, обработка и отправка пакетов.
Чаще всего эффективно работают схемы один поток на один сокет или один поток на два сокета, где первый сокет прослушивает порт, а другой используется для отправки данных.
Если более одного потока используют один сокет, могут возникать ошибки, а некоторые системы не различают потоки и процессы. Поэтому рекомендую создавать сокеты в том потоке, в котором планируете их использовать и пользоваться только в нём.
Если входящий трафик накатывает "волнами" есть смысл организовать "почтовый ящик". см. ddos.