-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
|
1 | |
Хочу изучить TCP/IP на самом глубоком уровне. Что "внутри" библиотеки ws2_32.dll (winsock)?22.11.2016, 02:28. Показов 8086. Ответов 48
Метки нет (Все метки)
Предисловие (можно не читать если не интересно)
Разрабатываю клиент-серверную архитектуру, от которой требуется высочайшая стабильность при любых проблемах с интернетом на клиенте - чтобы клиент работал на всех 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
|
22.11.2016, 02:28 | |
Ответы с готовыми решениями:
48
Сформировать N-уровневый вложенный список, элементом которого на самом глубоком уровне является число N Создает на n - уровне вложенный список, элементом которого на самом нижнем уровне является n точка входа в процедуру inet_pton не найдена в библиотеке dll ws2_32.dll Проверка данных внутри библиотеки dll |
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
|||||||||||
11.12.2016, 13:12 [ТС] | 41 | ||||||||||
Убежденный,
Могут перемешаться сами буфера, в смысле прийти в разном порядке. То есть если я сделаю так:
Но они вроде и без потоков могут перемешаться. Поэтому я вообще не буду делать так. На каждый "пакет" моего протокола будет всего один send, то есть вот так у меня будет:
Теперь насчет recv, здесь конечно сложнее, ибо не зная размер "пакета" я не могу весь "пакет" считать одним вызовом recv, поэтому будет путаница, но и она решается с помощью алгоритма конечного автомата хоть и говнокод это будет. Но recv у меня, скорее всего, и не будут в разных потоках. Но по-моему такой алгоритм уже есть в ОС, только надо правильно его настроить, думаю что вот у меня на клиенте он правильно настроен, а на сервере нет. В общем, завтра буду смотреть
0
|
Ушел с форума
|
|
11.12.2016, 13:18 | 42 |
Еще как могут. Если ты сделаешь send на один и тот же сокет из разных потоков
одновременно, то система не даст тебе никаких гарантий на счет порядка данных. Не могут. Если send вызывается на одном и том же сокете последовательно, т.е. каждая следующая операция вызывается строго после того, как отработала предыдущая, данные никогда перемешаны не будут. И напрасно. Такая конструкция полностью безопасна (надо только добавить проверку возвращаемого значения у каждого send). Это не говнокод, именно так и работают, например, HTTP-серверы. Как, по-твоему, они определяют конец одного HTTP-сообщения и начало другого? Правильно, там стейт-машина с парсингом протокола. Ну здесь прелесть именно в том, что ты не зависишь от настроек ОС.
0
|
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
|
11.12.2016, 13:35 [ТС] | 43 |
Убежденный,
Я отправлю 2 буфера в разных потоках (специально взял очень малый размер чтобы каждый отправлялся 1 сегментом) Код
send("1234"); - поток 1 send("ABCD"); - поток 2 Код
12C4 - дата из сегмента 1 AB3D - дата из сегмента 2 Или байты в заголовках TCP-сегментов тоже могут перемешаться? Слушай, я в принципе могу извратиться и сделать на клиенте всего 2 потока - в одном while read, в другом write, и в этом втором будут и heartbeatы и команды и все остальные write. И тоже самое на сервере - на каждый клиент один сокет и два потока. Но это усложняет и без того сложную задачу, поэтому не вводи меня в заблуждение, пожалуйста. А то с таким же успехом у тебя окажется, что и printf (вывод в консоль) нельзя вызывать сразу в нескольких потоках, и т.п. На это забей. Этого просто не будет. Read для 1 сокета будет в 1 потоке и на сервере и на клиенте.
0
|
Ушел с форума
|
|
11.12.2016, 14:45 | 44 |
Могут. Хотя бы потому, что до того, как данные превратятся в сегменты, они
должны пройти еще много промежуточных уровней - WinSock Providers, msafd, afd.sys, tcpip.sys и т.д. Вот что сказано по поводу функции send в MSDN: Ок.
0
|
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
|
11.12.2016, 14:56 [ТС] | 45 |
Убежденный,
И что в итоге принимается другой стороной? Вот я у себя не наблюдал такого, чтобы аж порядок байт в одном сегменте перемешивался при многопоточности. Наверно, у меня этого нет. Так какие условия должны измениться (ОС, железо...), чтобы это было? На эти вопросы ты, очевидно, не ответишь. Придется пока решать остальные проблемы, а там видно будет, может код даже проще для восприятия станет благодаря отказу от многопоточных send. В любом случае проведу испытания.
0
|
Ушел с форума
|
|
11.12.2016, 15:22 | 46 |
Видишь ли, для TCP размер буфера, который ты передаешь в send - не указ.
Компоненты сетевого стека, которые расположены ниже send, могут передавать этот буфер хоть по одному байту по сети. То есть, в каждом сегменте может быть хоть по одному байту данных и это не будет каким-то нарушением спецификации TCP. Пока твои данные в send будут проходить многочисленные уровни сетевого стека, они уже там, еще до превращения в сегменты, могут быть раздроблены на произвольное количество частей. В результате на принимающей стороне ты получишь "перемешанные" данные. Вот почему в TCP так важно соблюдать строгую очередность по отношению к send-send или recv-recv. Тебе цитаты из MSDN не достаточно? Ну напиши тест. Например, где несколько потоков в параллель, без задержек, в цикле "бомбят" один и тот же сокет функциями send. А сервер читает данные и смотрит, были ли нарушения в последовательности данных. Я вот однажды уже приводил похожий тест, который доказывает, что фрагментация TCP-потока возможна и в локальных сетях, и даже на localhost: TCP протокол отправка данных на сервер Я думаю, результаты такого теста будут интересны очень многим и многие скажут спасибо. Ну если ты боишься, что я ставлю себе цель непременно ввести в заблуждение...
0
|
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
|
11.12.2016, 15:31 [ТС] | 47 |
Убежденный,
А какие еще тесты можно провести подобные? То есть с потоками и с проблемой путаницы. Например, с файлами на диске есть ли такое, если я с каждым вызовом WriteFile буду писать новую строчку в файл, то перепутаются только строчки, или и символы в них? Добавлено через 2 минуты
0
|
Ушел с форума
|
|
11.12.2016, 15:58 | 48 |
А откуда ты знаешь, как себя ведут стандартные сетевые провайдеры и драйверы в этом отношении?
Уверен на 100%, что они всегда ставят блокировку на параллельный доступ к буферам с данными? С дисками вообще все очень сложно. Даже если у тебя две или более операций записи выполнены строго последовательно, то даже в этом случае нет гарантий, что они попадут на физическое устройство именно в таком порядке. Современные дисковые контроллеры могут переупорядочивать обращения к разным секторам. И, например, если будет power failure, то при включении компьютера может оказаться, что более поздние данные успели записаться, а более ранние - нет Это, кстати, большая головная боль разработчиков баз данных и прочих систем, к которым предъявляются соответствующие требования в плане надежности и других гарантий (ACID и т.п.). Так что прямых аналогий с диском, наверное, провести нельзя. Большинству. Кроме некоторых. Я тоже люблю засовывать голову под капот и изучать, почему так и этак. Всегда полезно знать, как устроена система изнутри, чтобы наиболее эффективно управлять ей снаружи. Это хорошо. Значит, моя помощь больше не требуется. От темы отписался.
0
|
-1 / 5 / 0
Регистрация: 22.11.2016
Сообщений: 68
|
||||||
11.12.2016, 16:01 [ТС] | 49 | |||||
Убежденный,
(помнишь, ты говорил, что в этом нет смысла т.к. не бывает "дырок" и в общем-то достаточно штатной чексуммы TCP, но многопоточность-то мы тогда не брали во внимание) , то мало не покажется. Не по теме:
А вот этот поможет, или там тоже байты путаются? :)
А насчет вопросов по алгоритму данной системы - я их вообще везде задаю, что-то новое узнаю почти от каждого, но конкретно по алгоритмам может дать справку только тот, кто именно писал подобную систему.
0
|
11.12.2016, 16:01 | |
11.12.2016, 16:01 | |
Помогаю со студенческими работами здесь
49
Как изучить WinSock Подключение библиотеки импорта Ws2_32.lib Хук на ws2_32.dll Сокеты через Ws2_32.dll Перехват Send(ws2_32.dll) Ошибка после подключения ws2_32.dll Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |