Перейти к содержимому

Что такое tcp сервер

  • автор:

Сетевое программирование — TCP | HTTP сервер

TCP и UDP — оба протоколы транспортного уровня. UDP — это протокол без установления соединения и с негарантированной доставкой пакетов. TCP (Transmission Control Protocol) — это протокол с установлением соединения и с гарантированной доставкой пакетов. Сначала происходит рукопожатие (Привет. | Привет. | Поболтаем? | Давай.), после чего соединение считается установленным. Далее по этому соединению туда и обратно посылаются пакеты (идет беседа), причем с проверкой, дошел ли пакет до получателя. Если пакет потерялся, или дошел, но с битой контрольной суммой, то он посылается повторно («повтори, не расслышал»). Таким образом TCP более надёжен, но он сложнее с точки зрения реализации и соответственно требует больше тактов / памяти, что имеет не самое последнее значение для микроконтроллеров. В качестве примеров прикладных протоколов, использующих TCP, можно назвать FTP, HTTP, SMTP и многие другие.

HTTP (Hypertext Transfer Protocol) — прикладной протокол, с помощью которого сервер отдаёт странички нашему браузеру. HTTP в настоящее время повсеместно используется во Всемирной паутине для получения информации с веб-сайтов. На картинке светильник на микроконтроллере с ОС Contiki на борту, в котором цвета задаются через браузер.

HTTP протокол текстовый и достаточно простой. Собственно вот так выглядит метод GET, посылаемый утилитой netcat на локальный IPv6 адрес сервера с лампочками:

Метод HTTP (англ. HTTP Method) обычно представляет собой короткое английское слово, записанное заглавными буквами, чувствительно к регистру. Каждый сервер обязан поддерживать как минимум методы GET и HEAD. Кроме методов GET и HEAD, часто применяется методы POST, PUT и DELETE. Метод GET используется для запроса содержимого указанного ресурса, в нашем случае тут GET /b HTTP/1.0 где путь /b отвечает за цвет (синий). Ответ сервера:

Код состояния (у нас 200) является частью первой строки ответа сервера. Он представляет собой целое число из трёх цифр. Первая цифра указывает на класс состояния. За кодом ответа обычно следует отделённая пробелом поясняющая фраза на английском языке, которая разъясняет человеку причину именно такого ответа. В нашем случае сервер отработал без ошибок, всё пучком (ОК).

Как запрос, так и ответ содержат заголовки (каждая строка — отдельное поле заголовка, пара имя-значение разделена двоеточием). Заканчиваются заголовки пустой строкой, после чего могут идти данные.

Мой браузер отказывается открывать локальный IPv6-адрес, поэтому в прошивке микроконтроллера прописан дополнительный адрес и такой же префикс также нужно назначить виртуальному сетевому интерфейсу симулятора:

Если curl отработал без ошибок, то ссылку можно спокойно открывать в браузере.

Здесь мы научим наш игрушечный TCP/IP стек понимать TCP протокол. Итак организация соединения по протоколу TCP начинается с т.н. трехстороннего квитирования (рукопожатия). Как всегда разобраться с сетью поможет Wireshark.

Когда требуется установить соединение с удалённым сервером, ему отправляется пакет с установленным флагом SYN, что означает инициализацию сессии. Тут есть поле Sequence Number (на картинке 1039510418), начальное значение этого поля выбирается случайным образом инициатором соединения.

screenshot

Сервер, в ответ на этот пакет, отвечает пакетом с битами SYN, ACK. Своё значение Sequence Number (на картинке 16770109) он тоже генерирует случайным образом. Также он должен заполнить поле Acknowledgment Number, которые будет равно сумме принятого Sequence Number плюс 1 т.е. 1039510419.

screenshot

Теперь инициатору подключения не остается ничего другого, как ответить ACK. Здесь Acknowledgment Number аналогично будет равно сумме принятого Sequence Number плюс 1 т.е. 16770110.

screenshot

С этого момента соединение считается установленным. Дальнейшие пакеты будут передавать уже полезную нагрузку – данные протоколов вышестоящих уровней. В отличие от UDP, тут на каждый пакет нужно отправлять подтверждение (флаг ACK), дабы удалённый узел знал, что отправленные им данные были успешно приняты. При этом так же происходит взаимное увеличение Sequence Number у сервера и у клиента, но только уже не на 1, а на размер отправляемых данных.

Для закрытия соединение удалённому узлу посылается пакет с установленным флагом FIN.

С точки зрения реализации TCP это классический конечный автомат. На картинке показаны как состояния сервера, так и клиента (разные цвета стрелок), на стрелках отображено событие/действие – например переход сервера (синяя стрелка) из состояния LISTEN в состояние SYN RECEIVED происходит по событию SYN, реакция на это событие отправить клиенту SYN+ACK в ответ:

Теперь немного кода. Приведенный ниже пример очень сильно упрощён, тут нет состояний и реализована только минианимальная логика, достаточная для обмена данными утилитой netcat.

Обработка полезных данных — выводим на экран, печатаем в UART:

screenshot

Чтобы вывести данные в дисплей, отправляем девайсу TCP-пакет на любой порт помощью netcat:

Будучи однажды создан, канал TCP может существовать «вечно». А что будет, если некорректно разорвать соединение т.е. без флага FIN ? Такая ситуация возможна, если например выдернуть какой-нибудь кабель. Оба и клиент и сервер в этом случае будут безуспешно долго ждать данных друг от друга. Для отслеживания и отключения таких «мертвых» соединений часто используют механизм keep-alive – некое служебное сообщение, которое отсылается периодически. Если ответ на него не получен, то соединение разрывается.

Что такое TCP и как он работает?

Протокол управления передачей (TCP) является одним из самых важных протоколов пакета Internet Protocols. Это наиболее широко используемый протокол для передачи данных в сети связи, такой как Интернет.

  • TCP — надежный протокол. То есть, приемник всегда отправляет отправителю положительное или отрицательное подтверждение о пакете данных, так что отправитель всегда имеет яркое представление о том, достигнут ли пакет данных адресату или ему нужно повторно отправить его.
  • TCP гарантирует, что данные достигнут назначенного адресата в том же порядке, в котором он был отправлен.
  • TCP ориентирован на соединение. TCP требует установления соединения между двумя удаленными точками перед отправкой фактических данных.
  • TCP обеспечивает механизм проверки и восстановления ошибок.
  • TCP обеспечивает сквозную связь.
  • TCP обеспечивает контроль потока и качество обслуживания.
  • TCP работает в режиме «точка-точка» Client / Server.
  • TCP обеспечивает полный дуплексный сервер, т. Е. Он может выполнять роли как получателя, так и отправителя.

Длина заголовка TCP составляет минимум 20 байтов и максимум 60 байт.

  • Source Port (16 бит). Он определяет порт источника процесса приложения на отправляющем устройстве.
  • Destination Port (16 бит) — определяет порт назначения процесса приложения на принимающем устройстве.
  • Sequence Number (32 бита) — порядковый номер байтов данных сегмента в сеансе.
  • Acknowledgement Number (32 бита). Когда установлен флаг ACK, это число содержит следующий порядковый номер ожидаемого байта данных и работает как подтверждение предыдущих полученных данных.
  • Data Offset (4 бита). В этом поле подразумеваются как размер заголовка TCP (32-разрядные слова), так и смещение данных в текущем пакете во всем сегменте TCP.
  • Reserved (3 бита) — зарезервировано для будущего использования, и все по умолчанию устанавливаются в ноль.
  • Флаги (по 1 бит)
    • NS — бит Nonce Sum используется сигнальным процессом Явного сообщения о перегрузке.
    • CWR. Когда хост получает пакет с установленным битом ECE, он устанавливает, что Congestion Windows Reduced подтверждает, что полученная от ЕС.
    • ECE — имеет два значения:
      • Если бит SYN очищен до 0, значит, ECE означает, что пакет IP имеет установленный бит CE (перегрузка).
      • Если бит SYN установлен в 1, ECE означает, что устройство поддерживает ECT.

      Адресация

      Связь TCP между двумя удаленными хостами выполняется с помощью номеров портов (TSAP). Номера портов могут варьироваться от 0 до 65535, которые делятся как:

      • Порты системы (0 — 1023)
      • Порты пользователей (1024 — 49151)
      • Частные / динамические порты (49152 — 65535)

      Управление подключениями

      Связь TCP работает в модели Server / Client. Клиент инициирует соединение, и сервер либо принимает, либо отклоняет его. Для управления подключением используется трехстороннее связывание.

      Установка соединения

      Клиент инициирует соединение и отправляет сегмент с порядковым номером. Сервер подтверждает это со своим собственным порядковым номером и ACK сегмента клиента, который является еще одним номером последовательности клиентов. Клиент после получения ACK своего сегмента отправляет подтверждение ответа сервера.

      Любой из серверов и клиентов может отправлять сегмент TCP с флагом FIN, установленным в 1. Когда принимающая сторона отвечает на это посредством ACKnowlinging FIN, это направление связи TCP закрывается и соединение освобождается.

      Управление полосой пропускания

      TCP использует концепцию размера окна, чтобы удовлетворить потребность в управлении пропускной способностью. Размер окна сообщает отправителю на удаленном конце, количество сегментов байтов данных, которое может получить приемник с этого конца. TCP использует медленную фазу запуска с использованием размера окна 1 и увеличивает размер окна по экспоненте после каждого успешного сообщения.

      Например, клиент использует размер окна 2 и отправляет 2 байта данных. Когда подтверждение этого сегмента получено, размер окна удваивается до 4, а следующий отправленный сегмент отправляется длиной 4 байта данных. Когда получено подтверждение 4-байтового сегмента данных, клиент устанавливает размер окна 8 и т. Д.

      Если упущено подтверждение, то есть данные, потерянные в транзитной сети или полученные NACK, размер окна уменьшается до половины, а медленная начальная фаза начинается снова.

      Контроль ошибок и контроль потока

      TCP использует номера портов, чтобы узнать, какой процесс приложения ему нужен для передачи сегмента данных. Наряду с этим он использует порядковые номера для синхронизации с удаленным хостом. Все сегменты данных отправляются и принимаются с порядковыми номерами. Отправитель знает, какой последний сегмент данных был принят Получателем, когда он получает ACK. Получатель знает о последнем сегменте, отправленном отправителем, ссылаясь на порядковый номер недавно полученного пакета.

      Если порядковый номер недавно полученного сегмента не совпадает с порядковым номером, который ожидал приемник, он отбрасывается и NACK отправляется обратно. Если два сегмента поступают с одинаковым порядковым номером, значение временной метки TCP сравнивается для принятия решения.

      Мультиплексирование

      Способ объединения двух или более потоков данных в один сеанс называется мультиплексированием. Когда клиент TCP инициализирует соединение с сервером, он всегда ссылается на четко определенный номер порта, который указывает на процесс приложения. Сам клиент использует случайный номер порта из частных пулов номеров портов.

      Используя TCP Multiplexing, клиент может взаимодействовать с несколькими различными процессами приложения за один сеанс. Например, клиент запрашивает веб-страницу, которая, в свою очередь, содержит различные типы данных (HTTP, SMTP, FTP и т. Д.), Тайм-аут сеанса TCP увеличивается, и сеанс остается открытым на более длительное время, так что накладные расходы на трехстороннюю рукопожатие могут избегать.

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

      Контроль перегрузок

      Когда большое количество данных подается в систему, которая не способна обрабатывать ее, происходит перегрузка. TCP управляет перегрузкой с помощью механизма Window. TCP устанавливает размер окна, говорящий на другом конце, сколько сегмента данных нужно отправить. TCP может использовать три алгоритма управления перегрузкой:

      • Аддитивное увеличение, мультипликативное уменьшение
      • Медленный старт
      • Время ожидания

      Управление таймером

      TCP использует различные типы таймеров для управления и управления различными задачами:

      Таймер сохранения:

      • Этот таймер используется для проверки целостности и действительности соединения.
      • Когда время ожидания сохраняется, хост отправляет пробник, чтобы проверить, существует ли соединение еще.

      Таймер повторной передачи:

      • Этот таймер поддерживает сеанс передачи данных с сохранением состояния.
      • Если подтверждение отправленных данных не будет получено в течение времени повторной передачи, сегмент данных будет отправлен снова.

      Постоянный таймер:

      • Сеанс TCP может быть приостановлен хостом, отправив Размер окна 0.
      • Чтобы возобновить сеанс, хосту необходимо отправить размер окна с некоторым большим значением.
      • Если этот сегмент никогда не достигнет другого конца, оба конца могут ждать друг друга в течение бесконечного времени.
      • Когда таймер Persist истекает, хост повторно отправляет свой размер окна, чтобы узнать другой конец.
        Persist Timer помогает избежать взаимоблокировок в общении.

      Timed-Wait:

      • После освобождения соединения один из хостов ждет времени с пометкой времени, чтобы полностью завершить соединение.
      • Это делается для того, чтобы убедиться, что другой конец получил подтверждение своего запроса о завершении соединения.
      • Выдержка может быть не более 240 секунд (4 минуты).

      Восстановление после аварий

      TCP — очень надежный протокол. Он предоставляет порядковый номер для каждого байта, отправленного в сегменте. Он обеспечивает механизм обратной связи, т.е. когда хост получает пакет, он привязан к ACK, чтобы ожидал пакет, имеющий следующий порядковый номер (если он не является последним сегментом).

      Когда TCP-сервер прерывает связь в середине и перезапускает его процесс, он отправляет трансляцию TPDU всем своим хостам. Затем хосты могут отправить последний сегмент данных, который никогда не был непризнан и продолжен.

      Свой асинхронный tcp-сервер за 15 минут с подробным разбором

      Ранее я представил пару небольших постов о потенциальной роли Spring Boot 2 в реактивном программировании. После этого я получил ряд вопросов о том, как работают асинхронные операции в программировании в целом. Сегодня я хочу разобрать, что такое Non-blocking I/O и как применить это знание для создания небольшого tcp–сервера на python, который сможет обрабатывать множество открытых и тяжелых (долгих) соединений в один поток. Знание python не требуется: все будет предельно просто со множеством комментариев. Приглашаю всех желающих!

      Мне, как и многим другим разработчикам, очень нравятся эксперименты, поэтому вся последующая статья будет состоять как раз из серии экспериментов и выводов, которые они несут. Предполагается, что вы недостаточно хорошо знакомы с тематикой, и будете охотно экспериментировать со мной. Исходники примеров можно найти на github.

      Начнем с написания очень простого tcp–сервера. Задача сервера будет заключаться в получении и печати данных из сокета и возвращения строки Hello from server!. Примерно так это выглядит:

      Здесь все довольно просто. Если вы не знакомы с понятием сокета, то вот очень простая и практическая статья. Мы создаем сокет, ловим входящие соединения и обрабатываем их согласно заданной логике. Здесь стоит обратить внимание на сообщения. При создании нового соединения с клиентом мы пишем об этом в консоль.

      Хочу сразу заметить, что не стоит серьезно вникать в листинги программ до полного прочтения статьи. Совершенно нормально, если что-то будет не совсем понятно в самом начале. Просто продолжайте чтение.

      Нет особого смысла в сервере без клиента. Поэтому на следующем этапе необходимо написать небольшой клиент для использования сервера:

      Важной особенностью здесь является тот факт, что мы в начале устанавливаем максимально возможное количество соединений, а только потом используем их для передачи/хранения данных.

      Давайте запустим сервер. Первое, что мы видим:

      Это означает, что мы успешно запустили наш сервер и он готов принимать входящие запросы. Запустим клиент и сразу увидим в консоли сервера (у вас порты могут быть другими):

      Что и следовало ожидать. В бесконечном цикле мы получаем новое соединение и сразу же обрабатываем данные из него. В чем тут проблема? Ранее мы использовали опцию server_socket.listen(10) для настройки сервера. Она означает максимальный размер очереди из еще не принятых подключений. Но в этом нет совершенно никакого смысла, ведь мы принимаем по одному соединению. Что предпринять в такой ситуации? На самом деле, существует несколько выходов.

      1. Распараллелить с помощью потоков/процессов (для этого можно, например, использовать fork или пул). Подробнее здесь.
      2. Обрабатывать запросы не по мере их подключения к серверу, а по мере наполнения этих соединений нужным количеством данных. Проще говоря, мы можем открыть сразу максимальное количество ресурсов и читать из них столько, сколько сможем (сколько необходимо на это процессорного времени в идеальном случае).

      Как можно понять по выводу, мы принимаем новые коннекты и данные почти параллельно. Более того, мы не ждем данных от нового подключения. Вместо этого мы устанавливаем новое.

      Как это работает?

      Дело в том, что все наши операции с ресурсами (а обращение к сокету относится к этой категории) происходят через системные вызовы операционной системы. Если говорить коротко, то системные вызовы представляют собой обращение к API операционной системы.

      Рассмотрим, что происходит в первом случае и во втором.

      Синхронный вызов

      Давайте разберем рисунок:

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

      Асинхронный вызов

      Теперь посмотрим на рисунок, который иллюстрирует асинхронный вызов:

      Первая стрелка, как и в первом случае, делает запрос к ОС (операционной системе) на получение данных из ресурсов. Но посмотрите, что происходит далее. Мы не ждем данных из ресурса и продолжаем работу. Что же делать нам? Мы отдали распоряжение ОС и не ждем результат сразу. Простейшим ответом будет самостоятельно опрашивать нашу систему на наличие данных. Таким образом, мы сможем утилизировать ресурсы и не блокировать наш поток.

      Но самом деле такая система не является практичной. Такое состояние, в котором мы постоянно смотрим на данные и ждем какого-то события, называется активным ожиданием. Минус очевиден: мы впустую тратим процессорное время в случае, когда информация не обновилась. Более правильным решением было бы оставить блокировку, но сделать ее «умной». Наш поток не просто ждет какого-то определенного события. Вместо этого он ожидает любое изменение данных в нашей программе. Именно так и работает функция select в нашем асинхронном сервере:

      Теперь можно вернуться к реализации нашего асинхронного сервера и взглянуть на него с новым знанием. Первое, что бросается в глаза, – метод работы. Если в первом случае наша программа выполнялась “сверху вниз”, то во втором случае мы оперируем событиями. Такой подход в разработке ПО называется событийно-ориентированным (event-driven development).

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

      Заключение

      Выбор подхода напрямую зависит от решаемой нами задачи. Позвольте задаче самой выбрать наиболее продуктивный подход. Например, популярный Javaвеб -сервер Tomcat использует потоки. Не менее популярный сервер Nginx использует асинхронный подход. Создатели популярного веб-сервера gunicorn на python пошли по пути prefork.

      Спасибо, что прочитали статью до конца! В следующий раз (уже скоро) я расскажу о прочих возможных неблокирующих ситуациях в жизни наших программ. Буду рад вас видеть и в следующих постах.

      Что такое tcp сервер

      If we are creating a connection between client and server using TCP then it has a few functionalities like, TCP is suited for applications that require high reliability, and transmission time is relatively less critical. It is used by other protocols like HTTP, HTTPs, FTP, SMTP, Telnet. TCP rearranges data packets in the order specified. There is absolute guarantee that the data transferred remains intact and arrives in the same order in which it was sent. TCP does Flow Control and requires three packets to set up a socket connection before any user data can be sent. TCP handles reliability and congestion control. It also does error checking and error recovery. Erroneous packets are retransmitted from the source to the destination.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Luxury Car Rental in Miami | Reserve a Premium Vehicle with RealCar