Различия между версиями 25 и 26
Версия 25 от 2008-07-05 17:08:46
Размер: 22594
Редактор: DmitryChistikov
Комментарий:
Версия 26 от 2008-07-05 18:19:47
Размер: 22975
Редактор: DmitryChistikov
Комментарий: Поабзацный перевод
Удаления помечены так. Добавления помечены так.
Строка 100: Строка 100:
 1. Все начинается с установления подключения. Подключение по TCP двустороннее, то есть данные передаются в обе стороны. Клиент - это тот, кто инициирует подключение ("программа, которая хочет"), а сервер - тот, кто на него отвечает ("программа, которая может"). Итак, инициатор - клиент - подключается к серверу. Данные в дальнейшем передаются как от клиента к серверу, так и от сервера к клиенту.   1. Все начинается с установления подключения. Подключение по TCP двустороннее, то есть данные передаются в обе стороны. Клиент - это тот, кто инициирует подключение ("программа, которая хочет"), а сервер - тот, кто на него отвечает ("программа, которая может"). Итак, инициатор - клиент - подключается к серверу. Данные в дальнейшем передаются как от клиента к серверу, так и от сервера к клиенту.
Строка 110: Строка 110:
''Окончание переведенной к настоящему моменту части'' -- DmitryChistikov <<DateTime(2008-07-05T18:08:45+0400)>> ''Дальше должен быть пример с tcpdump - где тайпскрипт? Пока тут лежит текст расшифровки.''
Строка 120: Строка 120:
Для того, чтобы выполнить задачу разделения данных, к паре (адрес отправителя,
адрес получателя) появляется ещё одно понятие --- порт. Оно участвует в
TCP, и оно же еще немножко помогает на уровне интерпретации данных.
''Конец примера с tcpdump.''
Строка 124: Строка 122:
Придумано оно по аналогии с портами ввода-вывода обычного компьютера.
Когда происходит установление соединения, то клиент подключается не просто к ip,
но к определенному ip и определенному порту этого самого сервера, что мы
только что проделали с помощью программы telnet, которая для этого как раз и
не предназначалась никогда. В качестве тестировщика она подходит.
Для того чтобы выполнить задачу разделения данных, пары "адрес отправителя - адрес получателя" недостаточно. Введем новое понятие - порт. Оно участвует в TCP и, кроме того, оказывается полезным на уровне интерпретации данных.
Строка 130: Строка 124:
Придумано оно по аналогии с портами ввода-вывода обычного компьютера. Когда происходит установление соединения, клиент подключается не просто к IP-адресу сервера, но к паре "IP сервера - некоторый порт". Именно это мы и проделали с помощью программы telnet. На самом деле эта программа не предназначалась для таких действий, однако тестирование с ее помощью проводить удобно. Вначале мы подключились по IP-адресу 89.188.104.91 на 80-й порт, а потом по тому же адресу, но на 22-й порт. Во втором случае, как видно, нас ожидал OpenSSH-сервер на Debian.
Строка 131: Строка 126:
Мы сначала подключились по этому (89.188.104.91) ip-шнику на 80-й порт, а потом
подключились по этому (89.188.104.91) ip-шнику на 22 порт, и в случае 22 нас ожидал
какой-то сервер, какой-то OpenSSH, какой-то Debian, понимаете ли...
Поскольку установление подключения двустороннее, то когда происходит ответное установление подключение от сервера к клиенту, оно происходит также по определенному порту. Его номер сообщается клиентом в самом начале соединения. В данном случае порт получателя - 22, а клиент передает номер 44670. Как видно, эти номера портов сохраняются и в дальнейшем. Если теперь мы будем устанавливать следующее подключение к тому же самому серверу, в качестве порта отправителя будет использовано другое число. Именно это число и будет отличать соответствующие потоки данных: IP-адрес получателя, порт получателя и IP-адрес отправителя не поменялись, а вот порт отправителя у них разный. Иными словами, каждое TCP-соединение использует свой собственный порт для идентификации отправителя. Таким образом, эта четверка (адрес и порт отправителя, адрес и порт получателя) и является идентификатором на транспортном уровне.
Строка 135: Строка 128:
Кстати, вы ключи обновили? --- М? --- Ключи обновили? --- Да, конечно. --- (Черт!) Опишем теперь, как используется порт на уровне приложений. Согласно некоторой договоренности, разные типы приложений традиционно принимают соединения на разных портах. Поэтому данные, приходящие на разные порты, естественно интерпретировать по-разному. При подключении по 80 порту то, что мы передаем, будет интерпретироваться как HTTP-запросы, а по порту 22 нас ждет Secure Shell (SSH). Несложно понять, зачем это соглашение понадобилось. Дело в том, что никакого другого способа указать клиенту, по какому порту подключаться, не существует (кроме, разумеется, словесного описания: "У меня есть сервер - подключайся, пожалуйста, по порту 9090").
Строка 137: Строка 130:
Поскольку установление подключения двустороннее, то когда происходит
ответное установление подключения от сервера к клиенту, оно происходит также
по определенному порту, который клиент ему просто сообщает, здесь
порт получателя это ssh (22), а у клиента это 44670, и он тут везде
сохраняется, как и порт ssh. Если вы устанавливаете следующее подключение к
тому же хотя бы, серверу, в качестве порта отправителя используется
произвольное другое число, именно поэтому вы можете различить эти два потока
данных, даже если адрес получателя, порт получателя и ip отправителя у них
одинаковый, а вот порт отправителя у них разный, потому что каждое
TCP-соединение использует свой собственный порт для идентификации отправителя.
Существует организация IANA, в которой можно зарегистрировать свое приложение, сказав: пусть теперь теперь такой-то порт исключительно вот для этого используется. Список зарегистрированных портов можно посмотреть в файле /etc/services:
Строка 148: Строка 132:
Так что эта четверка (адрес и порт отправителя, адрес и порт получателя) и
есть некий такой TCP-адрес, адрес уровня транспорта, идентификатор, вернее
так. TCP. Да.
''Здесь должен лежать тайпскрипт с `cat /etc/services/` с ПСПО.''
Строка 152: Строка 134:
Почему лектор говорит, что порт это такой переходный уровень между TCP и
уровнем приложений? Дело в том, что согласно некоторой договорённостям,
разные типы приложений сидят на разных портах, можем ожидать, как
интерпретировать данные, которые посыпятся на определенный порт, т.е. при
подключении по 80 порту то что мы передаем будет интерпретироваться как
HTTP-запросы, а по порту 22 нас ждет Secure Shell. Почему так? Да потому
что никакого другого способа указать клиенту, по какому порту как
подключаться, мы не имеем. Мы можем, конечно, словами сказать, вот у меня есть
сервер, ты подключайся, пожалуйста, по порту 9090. Лектор на стриме завёл
барахло, на 9090 порту, кто знал, тот ходил.
Можно заметить, что временный порт для подключения всякий раз выбирается достаточно большим. На самом деле он должен быть больше 32000 (в некоторых случаях это нужно).
Строка 163: Строка 136:
Существует организация IANA, в которой вы можете зарегистрировать своё
приложение, сказав: пускай теперь такой-то порт теперь исключительно вот для
этого используется. (cat /etc/services).
Known ports, так называемые. Как вы могли заметить,
временный порт выбирается достаточно большим, кажется он должен быть больше
32000, есть такая традиция, в некоторых случаях это нужно.
Расскажем напоследок, в чем разница между TCP-пакетами и UDP-датаграммами. На самом деле в них нет почти ничего общего. Конечно, есть IP-адреса и порты получателя и отправителя. И тем не менее, это так. Если на прикладном уровне не организовано специальной поддержки подтверждений, UDP-датаграмма может уйти "в никуда". И, разумеется, есть класс задач, где это единственно возможная организация передачи данных. Классический пример - широковещание. Никому не придет в голову от всех клиентов, которые смотрят потоковое видео, получать подтверждения и сообщения об ошибках и обрабатывать их. Другая область применения - случай, когда сам факт обмена данных заключается в посылке очень маленьких пакетов, а работа на прикладном уровне подразумевает, что ответ будет отправлен. Типичный пример - DNS. Если мы ждем ответа от DNS-сервера, то его можно ждать и на прикладном уровне - с таким же успехом, как и на уровне установления TCP-соединения. Незачем из одного пакета делать четыре - разумнее экономить трафик, причем чем выше уровень DNS-сервера, тем это выгодней.
Строка 170: Строка 138:
Вопросы Есть и еще одно соображение, которое стоит рассмотреть. Предположим, у нас есть очень медленный (по времени отклика) канал. Оказывается, по такому каналу удобнее "гонять" UDP. Это хорошо видно из следующей схемы:
Строка 172: Строка 140:
В чём разница между TCP-пакетами и UDP-датаграммами? ''Здесь должна лежать схема.''
Строка 174: Строка 142:
В них нет почти ничего общего. Нет, ip и порт есть, даже порт отправителя, что
удивительно. Если на прикладном уровне не сделано своей поддержки
подтверждений, мы можем свой udp-пакет послать вникуда, и он уйдёт вникуда,
есть класс задач, где только так себя и нужно вести, например широковещание,
не хватало нам от всех клиентов, которые смотрят наше потоковое видео,
получать подтверждения и сообщения об ошибках, и обрабатывать их.
Другая область применения, когда сам факт обмена данных заключается в посылке
очень маленьких пакетов, а сама работа на прикладном уровне подразумевает, что будет
отчет, типичный пример -- это dns, незачем из одного пакета делать 4. И если
мы ждем ответа от dns-сервера, то его можно ждать и на прикладном уровне, с
тем же успехом, как ждать установления tcp-соединения. Траффик экономится, и
чем выше уровень DNS-сервера, тем выгоднее экономить его. Сетевые файловые
системы, NFS, раньше использовали UDP. Тут забавная ситуация. Если у вас очень
медленный (по времени ответа) канал, то в действительности по нему удобно гонять,
как ни странно, именно udp. Надо оценивать, в том числе и случай возникновения
ошибки, т.к. если мы узнаем о ней поздно, то уже можем успеть послать много
лишних пакетов. В современности среды передачи данных работают все быстрее,
компьютеры работают еще быстрее, а надёжность не повышается, на 1000 пакетов
один зажёвывается. И получается, что с установлением соединения теперь получается
быстрее.
На самом деле надо оценивать еще и случай возникновения ошибки: если мы узнаем о ней слишком поздно, то будет послано много лишних пакетов. В современном мире среды передачи данных и компьютеры работают все быстрее, а уровень надежности не повышается. Поэтому и в таких случаях становится все выгоднее использовать протокол с установлением соединения. Классический пример такого перехода - сетевые файловые системы (NFS), переходящие с UDP на TCP.
Строка 195: Строка 144:
{03:27:40}
Строка 202: Строка 150:
|| 27 || 1 || 1 || 1 || || 1 || (кто?), DmitryChistikov || 03.07.2008 || || 30 || 1 || 1 || 1 || || 1 || (кто?), DmitryChistikov || 03.07.2008 ||

Транспортный уровень

Рассмотрим теперь четвертый уровень - уровень TCP. Третий уровень дал нам теоретическую возможность доставить пакет до получателя. На четвертом решается вопрос реализации этой возможности:

  • Нужно обеспечить подтверждение получения данных.

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

Должны мы предусмотреть и следующие возможности:

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

Возможна такая ситуация: данные были отправлены, но абонент ничего не получил. Пусть передаваемая информация разделена, скажем, на четыре пакета, которые отправляются последовательно, один за другим. Допустим, что абонент получает 1-й, 2-й и 4-й пакеты (3-й потерялся "по пути"). Нужно разработать механизм объединения этих четырех пакетов в поток так, чтобы получатель понял, что он не получил именно 3-й пакет (то есть тот 4-й, который он получил, есть именно 4-й, а не 3-й). В противном случае при "перемешивании" пакетов (например, в результате причуд маршрутизации вначале придет 4-й пакет, а только потом - 3-й) будет невозможно восстановить исходный порядок пакетов, а следовательно и передваваемую информацию. Итак, необходимо решить вопрос манипулирования потоком данных.

  • Перед тем как отправлять данные, нужно удостовериться, что абонент существует и может их принять.

Разумеется, начать следует с решения вопроса о подключении. Иными словами, перед тем как данные передавать, следует убедиться в том, что есть кому их принимать. К примеру, мы хотим отправить данные абоненту с адресом 158.250.10.1. Однако "существует" ли он для нас - априори неизвестно. Даже в случае его существования мы не можем гарантировать, что маршрут, по которому пойдет пакет, функционирует корректно. Прежде чем начать передачу данных данному абоненту, следует обменяться с ним вспомогательной информацией. Если абонент не отвечает, то "добраться" до него мы не сможем, так что передавать данные бессмысленно.

  • Обеспечить возможность манипулирования потоками данных.

Однако всегда ли необходимо решение всех пяти перечисленных задач? Ясно, что если вся информация, которую надо передать, помещается в один пакет (датаграмму), то можно пойти более простым путем. Чтобы была возможность выбора, на уровне TCP поддерживается два протокола: надежный (TCP) и ненадежный (UDP).

Еще про манипуляцию потоков данных. Она нужна вот для чего: когда мы передаем сразу два потока данных, нужно сделать так, чтобы эти потоки друг от друга отличались.

Итак, у нас есть пять задач:

  • подключение,
  • подтверждение доставки,
  • контроль за целостностью данных,
  • манипуляция потоками данных,
  • отслеживание качества канала.

Эти пять задач обыкновенно решаются именно на уровене TCP. Можно считать, что это пять требований к решению вопроса доставки.

Итак, помимо TCP существует еще и UDP. Следует разобраться, когда какой протокол использовать. Разберем подробнее наш пример. Допустим, мы хотим послать ровно один пакет. Зачем нам организация из него потока данных? Зачем отслеживание качества канала? Зачем, в конце концов, подключение? Если вся информация, которую мы собираемся передавать, умещается в один акт передачи данных, то ничего из перечисленного организовывать не нужно. В крайнем случае - переложить на "вышележащий" протокол. Почему так? Дело в том, что проверка контрольной суммы осуществляется и при использовании протокола UDP, поэтому единственная возможная проблема - потеря пакета. Но в случае соединения по протоколу TCP дела обстоят не лучше: если первый пакет в соединении не дошел до абонента, то соединение просто не установится. Следовательно, в нашем случае разумно использовать UDP, а потом просто проверить: дошел ли наш пакет? К примеру, именно так устроен протокол DNS: на UDP-запрос должен прийти ответ, который, с одной стороны, подтверждает корректную доставку и, с другой стороны, несет содержательную информацию.

Именно по этой причине на уровне TCP всего два протокола. Если на уровне IP протоколов гораздо больше (к примеру, протоколы туннелирования, L2TP и прочие), то здесь их в точности два. Один из них пять перечисленных свойств поддерживает - это TCP. Другой же не поддерживает ни одного из них, потому что все заключено в одной посылке данных, - это UDP.

TCP

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

  1. Все начинается с установления подключения. Подключение по TCP двустороннее, то есть данные передаются в обе стороны. Клиент - это тот, кто инициирует подключение ("программа, которая хочет"), а сервер - тот, кто на него отвечает ("программа, которая может"). Итак, инициатор - клиент - подключается к серверу. Данные в дальнейшем передаются как от клиента к серверу, так и от сервера к клиенту.
  2. TCP устроен по принципу подтверждения: на каждый TCP-пакет (а он может быть гораздо больше, чем IP-пакет!), после того как он принят сервером, генерируется подтверждение, если все принято (все хорошо), или сообщение об ошибке, в случае если пакет "побился" по дороге. Сообщение об ошибке отправляется также в том случае, когда приходит что-то из того же потока данных, но не соответствующее ожиданиям. Это возможно, к примеру, когда в некоторый момент происходит timeout и некоторого пакета (или группы пакетов) внутри потока данных не приходит вообще: "Ты что мне шлешь 12-й? Я хочу 3-й!" Процесс это симметричный, подобно игре в волейбол. Данные, связанные с управлением, и собственно передаваемые данные можно объединять. Допустим, клиент посылает пакет серверу, а тот посылает ответ (подтверждение) вместе со своими данными. Разумеется, может прийти и просто подтверждение, если посылать ничего не требуется.
  3. Все TCP-пакеты перенумерованы: в каждом соединении есть два счетчика seqn (sequence number) - по одному на каждое направление передачи. Счетчик инициализируется произвольно взятым числом при подключении и в дальнейшем увеличивается на объем передаваемых данных при каждой отсылке пакета. Такая схема позволяет, с одной стороны, определять последовательность пакетов и, с другой стороны, выяснять, что пропало и не сдублировался ли пакет.
  4. В каждом пакете передается также так называемая контрольная сумма, которая позволяет осуществлять контроль за целостностью данных.
  5. Что касается отслеживания качества канала, то в TCP используется довольно хитрая технология. Не вдаваясь в ее описание, заметим, что главная используемая идея такова: вначале обмен идет маленькими пакетами, а далее этот обмен происходит чем успешнее, тем быстрее (чем больше данных готова принять принимающая сторона, тем больше данных отправляет отправитель).

Дальше должен быть пример с tcpdump - где тайпскрипт? Пока тут лежит текст расшифровки.

(tcpdump host esyr.org) (Esc+_ --- вставить последний аргумент предыдущей команды в место курсора) а теперь второе окошечко, и скажем telnet. Вот тут Esc+_ работать не будет... вовсю тут фигачат... вот оно здесь началось, вот мы со своего адреса пошли на msk-f41.host-telecom на 22, вот наш sequence number с окном нулевой длины, вот они пришёл с нулевым окном обратно, и вот он пошел дальше увеличиваться, тык-тык-тык.

Конец примера с tcpdump.

Для того чтобы выполнить задачу разделения данных, пары "адрес отправителя - адрес получателя" недостаточно. Введем новое понятие - порт. Оно участвует в TCP и, кроме того, оказывается полезным на уровне интерпретации данных.

Придумано оно по аналогии с портами ввода-вывода обычного компьютера. Когда происходит установление соединения, клиент подключается не просто к IP-адресу сервера, но к паре "IP сервера - некоторый порт". Именно это мы и проделали с помощью программы telnet. На самом деле эта программа не предназначалась для таких действий, однако тестирование с ее помощью проводить удобно. Вначале мы подключились по IP-адресу 89.188.104.91 на 80-й порт, а потом по тому же адресу, но на 22-й порт. Во втором случае, как видно, нас ожидал OpenSSH-сервер на Debian.

Поскольку установление подключения двустороннее, то когда происходит ответное установление подключение от сервера к клиенту, оно происходит также по определенному порту. Его номер сообщается клиентом в самом начале соединения. В данном случае порт получателя - 22, а клиент передает номер 44670. Как видно, эти номера портов сохраняются и в дальнейшем. Если теперь мы будем устанавливать следующее подключение к тому же самому серверу, в качестве порта отправителя будет использовано другое число. Именно это число и будет отличать соответствующие потоки данных: IP-адрес получателя, порт получателя и IP-адрес отправителя не поменялись, а вот порт отправителя у них разный. Иными словами, каждое TCP-соединение использует свой собственный порт для идентификации отправителя. Таким образом, эта четверка (адрес и порт отправителя, адрес и порт получателя) и является идентификатором на транспортном уровне.

Опишем теперь, как используется порт на уровне приложений. Согласно некоторой договоренности, разные типы приложений традиционно принимают соединения на разных портах. Поэтому данные, приходящие на разные порты, естественно интерпретировать по-разному. При подключении по 80 порту то, что мы передаем, будет интерпретироваться как HTTP-запросы, а по порту 22 нас ждет Secure Shell (SSH). Несложно понять, зачем это соглашение понадобилось. Дело в том, что никакого другого способа указать клиенту, по какому порту подключаться, не существует (кроме, разумеется, словесного описания: "У меня есть сервер - подключайся, пожалуйста, по порту 9090").

Существует организация IANA, в которой можно зарегистрировать свое приложение, сказав: пусть теперь теперь такой-то порт исключительно вот для этого используется. Список зарегистрированных портов можно посмотреть в файле /etc/services:

Здесь должен лежать тайпскрипт с cat /etc/services/ с ПСПО.

Можно заметить, что временный порт для подключения всякий раз выбирается достаточно большим. На самом деле он должен быть больше 32000 (в некоторых случаях это нужно).

Расскажем напоследок, в чем разница между TCP-пакетами и UDP-датаграммами. На самом деле в них нет почти ничего общего. Конечно, есть IP-адреса и порты получателя и отправителя. И тем не менее, это так. Если на прикладном уровне не организовано специальной поддержки подтверждений, UDP-датаграмма может уйти "в никуда". И, разумеется, есть класс задач, где это единственно возможная организация передачи данных. Классический пример - широковещание. Никому не придет в голову от всех клиентов, которые смотрят потоковое видео, получать подтверждения и сообщения об ошибках и обрабатывать их. Другая область применения - случай, когда сам факт обмена данных заключается в посылке очень маленьких пакетов, а работа на прикладном уровне подразумевает, что ответ будет отправлен. Типичный пример - DNS. Если мы ждем ответа от DNS-сервера, то его можно ждать и на прикладном уровне - с таким же успехом, как и на уровне установления TCP-соединения. Незачем из одного пакета делать четыре - разумнее экономить трафик, причем чем выше уровень DNS-сервера, тем это выгодней.

Есть и еще одно соображение, которое стоит рассмотреть. Предположим, у нас есть очень медленный (по времени отклика) канал. Оказывается, по такому каналу удобнее "гонять" UDP. Это хорошо видно из следующей схемы:

Здесь должна лежать схема.

На самом деле надо оценивать еще и случай возникновения ошибки: если мы узнаем о ней слишком поздно, то будет послано много лишних пакетов. В современном мире среды передачи данных и компьютеры работают все быстрее, а уровень надежности не повышается. Поэтому и в таких случаях становится все выгоднее использовать протокол с установлением соединения. Классический пример такого перехода - сетевые файловые системы (NFS), переходящие с UDP на TCP.


Сведения о ресурсах

Готовность (%)

Продолжительность (ак. ч.)

Подготовка (календ. ч.)

Полный текст (раб. д.)

Предварительные знания

Level

Maintainer

Start date

30

1

1

1

1

(кто?), DmitryChistikov

03.07.2008


PspoClasses/080702/05TCP (последним исправлял пользователь eSyr 2009-03-22 23:06:33)