Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/40: Рейтинг темы: голосов - 40, средняя оценка - 4.95
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
1

Хочу изучить TCP/IP на самом глубоком уровне. Что "внутри" библиотеки ws2_32.dll (winsock)?

22.11.2016, 02:28. Показов 8086. Ответов 48
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Предисловие (можно не читать если не интересно)

Разрабатываю клиент-серверную архитектуру, от которой требуется высочайшая стабильность при любых проблемах с интернетом на клиенте - чтобы клиент работал на всех Windows от XP до 8.1, и x86 и x64, и при критически низкой скорости интернета, и при пропаданиях подключения в любое время и при любой продолжительности.
Соединение должно быть открыто постоянно 24/7 (пока не будет обрыва - тогда оно восстанавливается, причем данные никогда не теряются)
Казалось бы, TCP должен из коробки многое уметь, но я видел то что:
- стандартный winsockовскийKeepAlive работает не всегда, сервер был Win XP x64, одна и та же клиентская программа на C# успешно работала если клиент взять Win 8.1 x64 и не работала если взять Win 7 x86, насколько помню - во втором случае просто не отправлялись пакеты Keep-Alive, а вдруг у меня еще и другие ОС будут, скажем линукс, разве там KeepAlive совместим? сомнения сомнения, вот и решил отказаться от него и делать свою реализацию то есть Heartbeat
- чексумма почему-то не проверяется ни в UDP ни в TCP, ну по крайней мере я вижу то что если отправлять достаточно большой буфер данных, и если уже при отправке на 2 секунды вынуть LAN-кабель (после чего вернуть назад), то пакет с "дыркой" из 0x0 байтов как ни в чем не бывало доходит до принимающего сокета и обрабатывается им, и никаких Exception нигде нету

Я уже частично выработал общий алгоритм:
1)Connect. Он повторяется сколь угодно раз до тех пор пока не перестанет бросать Exception
2)Write обязательно вызывается только один раз для одного сообщения (для одного byte[])
2.1)в этот отправляемый byte[] нужно перед данными еще записать кастомную чексумму (ну раз стандартная не проверяется), и записать размер пакета в байтах чтобы сервер знал сколько выделить памяти для чтения пакета, и в самом начале еще фиксированное число байт для идентификации (потому что не успел я на рабочем сервере запустить очередную версию своей системы для теста, как посыпались пакеты от каких-то неадекватных ботов, что сломало сервер)
3)на сервере Read, у которого обязательно обработка Exception в случае если соединение пропадет уже к моменту вызова Read
3.1)а на случай "дырок" (см. выше) данные нужно читать в цикле, маленькими буферами байт по 10, получая сколько байт по факту считано и тем самым отсеивая "дырки" (это вроде бы получилось сделать)
3.2)затем данные сверяются с чексуммой, если не совпадает то пакет нужно перезапросить то есть в этом случае принимающая и передающая стороны меняются местами
3.2.1)и вообще в любом случае принимающая сторона должна давать ответ об успехе или неудаче (неудача=перезапрос)
4)учесть, что пакет перезапрашивающий данные тоже может дойти не верным, так что все перечисленное к нему тоже применяется, тогда его тоже перезапросить надо, и так до бесконечности пока проблема не исчезнет

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

Но надежды это хорошо, а я бы хотел иметь знания, достоверно изучить тему до уровня Tx/Rx которые в сетевом кабеле, увидеть все своими глазами, это и в будущем пригодится, с железом вроде различных микроконтроллеров (и даже "заказных" микросхем типа черных "капель"!) придется иметь тесные отношения.

И вот вопросы:

1) что "внутри" ws2_32.dll?
насколько знаю, в Windows есть сетевой драйвер - это служба, он напрямую работает с Tx/Rx (или как-то через BIOS? UEFI?), а с другой стороны есть ws2_32, который работает с драйвером.
по каком "протоколу", каким способом ws2_32 связан с драйвером? это случайно не ZwOpenFile (часто применяемый для связи с драйверами)?

2) возможно ли работать с этим драйвером напрямую без ws2_32?
не пугайтесь - этого не будет в продакшн, просто исследование

3) возможно ли спуститься еще глубже драйвера и напрямую работать с Tx/Rx/BIOS/UEFI? опять же в продакшне этого не будет, тем более это уже даже не user-mode, а нечто близкое к нулевому кольцу, вопрос только в том - насколько сложно, сколько вообще времени займет это исследование?

Внимание!
P.S. Вопрос не по сетям в целом, а только по ОС Windows, я понимаю то что можно и линукс (андроид) сюда подключить, но
если я буду одновременно две ОС исследовать, то мне уж точно никакого времени не хватит
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.11.2016, 02:28
Ответы с готовыми решениями:

Сформировать N-уровневый вложенный список, элементом которого на самом глубоком уровне является число N
Мужики помогите, задание программы- Формировать N-уровневый вложенный список, элементом которого на...

Создает на n - уровне вложенный список, элементом которого на самом нижнем уровне является n
Я решил задачу так: CL-USER 1 > (defun f (l n) (cond (( eq n 0) l) ((null l) (f...

точка входа в процедуру inet_pton не найдена в библиотеке dll ws2_32.dll
Привет! Почему когда я запускаю игру у меня появляется ошибка "точка входа в процедуру inet_pton...

Проверка данных внутри библиотеки dll
Есть библиотека, в которой хранятся различные методы. Для простоты, пусть в этой библиотеке есть...

48
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
11.12.2016, 13:12  [ТС] 41
Author24 — интернет-сервис помощи студентам
Убежденный,
делать параллельно send-send или recv-recv на одном сокете точно нельзя.
0_o Это ты вообще что-то не то говоришь. Байты в отправляемых буферах не перемешиваются друг с другом
Могут перемешаться сами буфера, в смысле прийти в разном порядке. То есть если я сделаю так:

C++
1
2
3
4
5
6
void hiLevelSend(string str) {
  tcp.send("bot_guard_magic_sequence");
  tcp.send(length(str));
  tcp.send(checksum(str));
  tcp.send(str);
}
Вот такую вот функцию нельзя вызывать в нескольких потоках, так как перемешаются эти фрагменты моего собственного протокола и нереально будет считать их в правильной последовательности.
Но они вроде и без потоков могут перемешаться. Поэтому я вообще не буду делать так. На каждый "пакет" моего протокола будет всего один send, то есть вот так у меня будет:

C++
1
2
3
4
5
6
7
void hiLevelSend(string str) {
  inmemorycontainer.add("bot_guard_magic_sequence");
  inmemorycontainer.add(length(str));
  inmemorycontainer.add(checksum(str));
  inmemorycontainer.add(str);
  tcp.send(inmemory_container.tobytesarray());
}
И вот такой вариант метода - уже можно вызывать в разных потоках одновременно. Он потокобезопасен.

Теперь насчет recv, здесь конечно сложнее, ибо не зная размер "пакета" я не могу весь "пакет" считать одним вызовом recv, поэтому будет путаница, но и она решается с помощью алгоритма конечного автомата хоть и говнокод это будет.
Но recv у меня, скорее всего, и не будут в разных потоках.

Я создаю сокет в асинхронном режиме - WSASocket. Делаю коннект на нужный адрес-порт.
Далее вызываю WSASend (или WSARecv - не важно). Обычно функция возвращает управление
немедленно, при этом в WSAGetLastError == WSA_IO_PENDING, т.е. передача началась.
Далее делается WaitForSingleObject или WaitForMultipleObjects с указанием желаемого таймаута, в
списке объектов ожидания которой должен быть указан хэндл сокета. Далее развитие событий такое:
либо Wait-функция вернет STATUS_TIMEOUT, т.е. истекло время ожидания, а операция так и
не была выполнена, либо она вернет WAIT_OBJECT_X, т.е. операция завершена, можно
получать ее статус и прочие параметры.
Я не столь хорошо знаю всю эту асинхронную кухню в WinAPI, но по-моему ты говоришь о велосипеде, то есть чтобы если recv спустя n секунд после send так ничего не вернул - то соединение считать обрывным.
Но по-моему такой алгоритм уже есть в ОС, только надо правильно его настроить, думаю что вот у меня на клиенте он правильно настроен, а на сервере нет. В общем, завтра буду смотреть
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
11.12.2016, 13:18 42
Цитата Сообщение от hemoa Посмотреть сообщение
0_o Это ты вообще что-то не то говоришь. Байты в отправляемых буферах не перемешиваются друг с другом
Еще как могут. Если ты сделаешь send на один и тот же сокет из разных потоков
одновременно, то система не даст тебе никаких гарантий на счет порядка данных.

Цитата Сообщение от hemoa Посмотреть сообщение
Но они вроде и без потоков могут перемешаться
Не могут. Если send вызывается на одном и том же сокете последовательно,
т.е. каждая следующая операция вызывается строго после того, как
отработала предыдущая, данные никогда перемешаны не будут.

Цитата Сообщение от hemoa Посмотреть сообщение
Поэтому я вообще не буду делать так
И напрасно.
Такая конструкция полностью безопасна (надо только добавить
проверку возвращаемого значения у каждого send).

Цитата Сообщение от hemoa Посмотреть сообщение
Теперь насчет recv, здесь конечно сложнее, ибо не зная размер "пакета" я не могу весь "пакет" считать одним вызовом recv, поэтому будет путаница, но и она решается с помощью алгоритма конечного автомата хоть и говнокод это будет.
Это не говнокод, именно так и работают, например, HTTP-серверы.
Как, по-твоему, они определяют конец одного HTTP-сообщения и начало другого?
Правильно, там стейт-машина с парсингом протокола.

Цитата Сообщение от hemoa Посмотреть сообщение
Я не столь хорошо знаю всю эту асинхронную кухню в WinAPI, но по-моему ты говоришь о велосипеде, то есть чтобы если recv спустя n секунд после send так ничего не вернул - то соединение считать обрывным.
Но по-моему такой алгоритм уже есть в ОС, только надо правильно его настроить, думаю что вот у меня на клиенте он правильно настроен, а на сервере нет.
Ну здесь прелесть именно в том, что ты не зависишь от настроек ОС.
0
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
11.12.2016, 13:35  [ТС] 43
Убежденный,
Если ты сделаешь send на один и тот же сокет из разных потоков
одновременно, то система не даст тебе никаких гарантий на счет порядка данных.
Насколько они могут перемешаться?
Я отправлю 2 буфера в разных потоках (специально взял очень малый размер чтобы каждый отправлялся 1 сегментом)
Код
send("1234"); - поток 1
send("ABCD"); - поток 2
И что, в итоге по сети может пойти вот такое:
Код
12C4 - дата из сегмента 1
AB3D - дата из сегмента 2
А как же чексуммы, в конце-то концов?
Или байты в заголовках TCP-сегментов тоже могут перемешаться?
Слушай, я в принципе могу извратиться и сделать на клиенте всего 2 потока - в одном while read, в другом write, и в этом втором будут и heartbeatы и команды и все остальные write. И тоже самое на сервере - на каждый клиент один сокет и два потока.
Но это усложняет и без того сложную задачу, поэтому не вводи меня в заблуждение, пожалуйста.
А то с таким же успехом у тебя окажется, что и printf (вывод в консоль) нельзя вызывать сразу в нескольких потоках, и т.п.

Это не говнокод, именно так и работают, например, HTTP-серверы.
Как, по-твоему, они определяют конец одного HTTP-сообщения и начало другого?
Правильно, там стейт-машина с парсингом протокола.
Я говорю о многопоточном Read и стейт-машине, которая для него будет необходима, так как каждый recv должен знать на какой секции заголовка тем временем остановился другой поток.
На это забей. Этого просто не будет. Read для 1 сокета будет в 1 потоке и на сервере и на клиенте.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
11.12.2016, 14:45 44
Цитата Сообщение от hemoa Посмотреть сообщение
Насколько они могут перемешаться?
Я отправлю 2 буфера в разных потоках (специально взял очень малый размер чтобы каждый отправлялся 1 сегментом)
C
1
2
send("1234"); - поток 1
send("ABCD"); - поток 2
И что, в итоге по сети может пойти вот такое:
C
1
2
12C4 - дата из сегмента 1
AB3D - дата из сегмента 2
А как же чексуммы, в конце-то концов?
Могут. Хотя бы потому, что до того, как данные превратятся в сегменты, они
должны пройти еще много промежуточных уровней - WinSock Providers, msafd,
afd.sys, tcpip.sys и т.д.

Вот что сказано по поводу функции send в MSDN:
send should not be called on the same stream-oriented socket concurrently from different threads,
because some Winsock providers may split a large send request into multiple transmissions,
and this may lead to unintended data interleaving from multiple concurrent send requests on
the same stream-oriented socket.
--------

Цитата Сообщение от hemoa Посмотреть сообщение
Слушай, я в принципе могу извратиться и сделать на клиенте всего 2 потока - в одном while read, в другом write, и в этом втором будут и heartbeatы и команды и все остальные write. И тоже самое на сервере - на каждый клиент один сокет и два потока.
Но это усложняет и без того сложную задачу, поэтому не вводи меня в заблуждение, пожалуйста.
Ок.

А то с таким же успехом у тебя окажется, что и printf (вывод в консоль) нельзя вызывать сразу в нескольких потоках, и т.п.
printf и send - это "слегка" разные вещи.
0
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
11.12.2016, 14:56  [ТС] 45
Убежденный,
send should not be called on the same stream-oriented socket concurrently from different threads,
because some Winsock providers may split a large send request into multiple transmissions,
and this may lead to unintended data interleaving from multiple concurrent send requests on
the same stream-oriented socket.
Так порядок сегментов путается, или порядок байт в одном сегменте, или что?
И что в итоге принимается другой стороной?
Вот я у себя не наблюдал такого, чтобы аж порядок байт в одном сегменте перемешивался при многопоточности. Наверно, у меня этого нет. Так какие условия должны измениться (ОС, железо...), чтобы это было?

На эти вопросы ты, очевидно, не ответишь.
Придется пока решать остальные проблемы, а там видно будет, может код даже проще для восприятия станет благодаря отказу от многопоточных send. В любом случае проведу испытания.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
11.12.2016, 15:22 46
Цитата Сообщение от hemoa Посмотреть сообщение
Так порядок сегментов путается, или порядок байт в одном сегменте, или что?
Видишь ли, для TCP размер буфера, который ты передаешь в send - не указ.
Компоненты сетевого стека, которые расположены ниже send, могут передавать этот буфер хоть
по одному байту по сети. То есть, в каждом сегменте может быть хоть по одному байту данных и
это не будет каким-то нарушением спецификации TCP. Пока твои данные в send будут проходить
многочисленные уровни сетевого стека, они уже там, еще до превращения в сегменты, могут
быть раздроблены на произвольное количество частей. В результате на принимающей стороне
ты получишь "перемешанные" данные. Вот почему в TCP так важно соблюдать строгую очередность
по отношению к send-send или recv-recv.

Цитата Сообщение от hemoa Посмотреть сообщение
Вот я у себя не наблюдал такого, чтобы аж порядок байт в одном сегменте перемешивался при многопоточности. Наверно, у меня этого нет. Так какие условия должны измениться (ОС, железо...), чтобы это было?
Тебе цитаты из MSDN не достаточно?
Ну напиши тест. Например, где несколько потоков в параллель, без задержек, в цикле "бомбят"
один и тот же сокет функциями send. А сервер читает данные и смотрит, были ли нарушения в
последовательности данных.

Я вот однажды уже приводил похожий тест, который доказывает,
что фрагментация TCP-потока возможна и в локальных сетях, и
даже на localhost:

TCP протокол отправка данных на сервер

Я думаю, результаты такого теста будут интересны очень многим и многие скажут спасибо.

Цитата Сообщение от hemoa Посмотреть сообщение
На эти вопросы ты, очевидно, не ответишь.
Ну если ты боишься, что я ставлю себе цель непременно ввести в заблуждение...
0
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
11.12.2016, 15:31  [ТС] 47
Убежденный,

Тебе цитаты из MSDN не достаточно?
Недостаточно, может там речь о ситуации, которая могла бы быть, но нет драйверов или WinSock-провайдеров, при которых бы она возникала.

Я думаю, результаты такого теста будут интересны очень многим и многие скажут спасибо.
Спс, посмотрим.
А какие еще тесты можно провести подобные? То есть с потоками и с проблемой путаницы.
Например, с файлами на диске есть ли такое, если я с каждым вызовом WriteFile буду писать новую строчку в файл, то перепутаются только строчки, или и символы в них?

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

Добавлено через 2 минуты
Я думаю, результаты такого теста будут интересны очень многим и многие скажут спасибо.
Большинству не интересны такие дебри. Я писал человеку диплом, вообще не зная ничего о TCP, кроме connect-write-read-close. Там жуть. И он этот диплом успешно защитил.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
11.12.2016, 15:58 48
Цитата Сообщение от hemoa Посмотреть сообщение
Недостаточно, может там речь о ситуации, которая могла бы быть, но нет драйверов или WinSock-провайдеров, при которых бы она возникала.
А откуда ты знаешь, как себя ведут стандартные сетевые провайдеры и драйверы в этом отношении?
Уверен на 100%, что они всегда ставят блокировку на параллельный доступ к буферам с данными?

Цитата Сообщение от hemoa Посмотреть сообщение
А какие еще тесты можно провести подобные? То есть с потоками и с проблемой путаницы.
Например, с файлами на диске есть ли такое, если я с каждым вызовом WriteFile буду писать новую строчку в файл, то перепутаются только строчки, или и символы в них?
С дисками вообще все очень сложно. Даже если у тебя две или более операций записи
выполнены строго последовательно, то даже в этом случае нет гарантий, что они попадут
на физическое устройство именно в таком порядке. Современные дисковые контроллеры
могут переупорядочивать обращения к разным секторам. И, например, если будет power failure,
то при включении компьютера может оказаться, что более поздние данные успели записаться, а
более ранние - нет

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

Так что прямых аналогий с диском, наверное, провести нельзя.

Цитата Сообщение от hemoa Посмотреть сообщение
Большинству не интересны такие дебри. Я писал человеку диплом, вообще не зная ничего о TCP, кроме connect-write-read-close. Там жуть. И он этот диплом успешно защитил.
Большинству. Кроме некоторых. Я тоже люблю засовывать голову под капот и изучать,
почему так и этак. Всегда полезно знать, как устроена система изнутри, чтобы наиболее
эффективно управлять ей снаружи.

Цитата Сообщение от hemoa Посмотреть сообщение
практического опыта с TCP у тебя маловато, ты не писал такую систему, как я сейчас пишу.
Это хорошо. Значит, моя помощь больше не требуется.
От темы отписался.
0
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
11.12.2016, 16:01  [ТС] 49
Убежденный,
Я тоже люблю засовывать голову под капот и изучать,
почему так и этак.
Мне приходится это делать. Если поезд с рельс сойдетна сервер придут перепутанные данные в "пакете", из-за того что на клиенте будет использоваться многопоточный send, а в моем протоколе даже не будет реализована своя чек-сумма для их проверки,
(помнишь, ты говорил, что в этом нет смысла т.к. не бывает "дырок" и в общем-то достаточно штатной чексуммы TCP, но многопоточность-то мы тогда не брали во внимание)
, то мало не покажется.

Не по теме:

С дисками вообще все очень сложно. Даже если у тебя две или более операций записи
выполнены строго последовательно
Жуть.
А вот этот поможет, или там тоже байты путаются? :)
C++
1
2
3
inmemorybuffer.add("lorem\r\n");
inmemorybuffer.add("ipsum\r\n");
WriteFile(inmemorybuffer);



Это хорошо. Значит, моя помощь больше не требуется.
Да как и вчера и позавчера - она нужна для того, чтобы ты мне выдал по конкретным вопросам сколько-то теории, пересказанной своими словами и без лишней "воды", как если бы я сам читал доки и книги.
А насчет вопросов по алгоритму данной системы - я их вообще везде задаю, что-то новое узнаю почти от каждого, но конкретно по алгоритмам может дать справку только тот, кто именно писал подобную систему.
0
11.12.2016, 16:01
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.12.2016, 16:01
Помогаю со студенческими работами здесь

Как изучить WinSock
Есть ли годная литература для c++?

Подключение библиотеки импорта Ws2_32.lib
Добрый вечер, при подключение библиотеки импорта Ws2_32.lib и соответственно заголовочного файла...

Хук на ws2_32.dll
День добрый всем. Нужна помощь коллективного разума. Пишу парсер трафика онлайн игры. Поставил хук...

Сокеты через Ws2_32.dll
Есть ли у кого работающий пример гет запроса на какой-нибудь сайт ? В нэте всё в DEV-C++ не...

Перехват Send(ws2_32.dll)
Создаю программу для ограничения доступа юзеров к определенным сайтам . Использую библиотеки для...

Ошибка после подключения ws2_32.dll
После подключения ws2_32.dll даже такой #include <iostream> #include <stdio.h> #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
49
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru