Непонятки с TCP/IP
Сервер на пурике принимает "пакет". В нем сначала идет 4-байтовый integer, в котором содержится полная длина последующего сообщения. Проблема в том, что очень редко и в рандомных случаях этот integer теряется, сразу идет сообщение. В таком случае сообщение обрабатывается, но следующий пакет, если он уже пришел, может быть утерян, так как неизвестно где данный заканчивается.:(
Может кто сталкивался? Очень неприятная проблема... |
Ответ: Непонятки с TCP/IP
Читаешь всегда ТОЧНО столько сколько ожидаешь?
При этом проверяй что прочтённая длина равна ожидаемой. Если меньше чем ожидал, значит жди ещё пока остаток данных не прийдёт, это редкость, т.к. обычно данные приходят обычно слитые, нежели разбитые (но и такое бывает). Так что читая 4 байта (заголовок), далее читай данные длины, и убедись что прочитал ровно столько, сколько ожидал, лишь потом освобождай блок для последующего чтения. Тут больше логическая проблема кода. |
Ответ: Непонятки с TCP/IP
Да я вообще не в понятках в чем проблема. Читаю ровно столько сколько отправляю - проверял в логах. Потеря заголовка проявляется очень редко и рандомно. Даже подряд когда отправляю 100 разных пакетов (без задержки между ними), проблема не вылезает, ну если только очень редко, - значит проблема не в логике. хз даже что делать то...((
|
Ответ: Непонятки с TCP/IP
Ты уверен что прочтённые данные длиной которой ожидаешь, и ты принял все что ожидал? При приёме, есть переменная с длиной.
Также, ты блокируешь чтение между началом чтения хедера и тела до полного прочтения тела? |
Ответ: Непонятки с TCP/IP
Вот код:
Код:
ReceiveNetworkData(TCPclientID,*TCPBuffer,4) В этом коде еще нет проверки на то, если сообщение пришло не полностью, но когда на одном компьютере тестишь - это проблем не вызывает, проверял. |
Ответ: Непонятки с TCP/IP
Ты запускаешь данную функцию по ассинхронному каллбеку, или один раз в цикле опрашиваешь?
Ты проверил что данные хедера все пришли (4 байта)? |
Ответ: Непонятки с TCP/IP
в цикле, проверка не нужна (в сообщение выше дописал)
|
Ответ: Непонятки с TCP/IP
У меня сомнения по этому коду:
Код:
If TCPlength>1000:TCPlength=1000:PrintN("Packet error!"):EndIf Ты уверен что проблем нету с подсчётом длины пакета? |
Ответ: Непонятки с TCP/IP
Уверен. А вот эта строчка выдает ошибку, но принудительно читает пакет, вместе с возможными кусками последующих пакетов. Этой строчки вообще не будет, если проблема перестанет проявлятся.
А выдает TCPlength.i=PeekL(*TCPBuffer) больше тысячи, потому что в памяти находится первые четыре байта пакета, а там символы, если считать их из памяти как integer, всегда получается больше 1000. Это типа проверка на ошибку пакета... Да, и по идее, у нормальных пакетов длина всегда меньше 1000. Забыл сказать - пакеты отправляю прогой на Blitz3D, пробовал двумя способами: Код:
;1 способ |
Ответ: Непонятки с TCP/IP
Ну почему число TCPlength в итоге больше 1000 это и так понятно.
Тут нету проверки сколько данных ты принял, это и вызывает проблему скорее всего. Т.к. в очень редких случаях ты примешь не достаточно данных (в сетевом стёке не всё ещё), а ожидаешь достаточно. Попробуй проверку замутить: Код:
ReceiveNetworkData(TCPclientID,*TCPBuffer,TCPlength) Лучше запости код где ты это делаешь, и опиши, делаешь ассинхронно или синхронно? |
Ответ: Непонятки с TCP/IP
Проверял я это все. Если бы принял недостаточно данных - то следующий PeekL(*TCPBuffer) выдал бы данные с середины предыдущего пакета - такого ни разу не было. Он всегда выдает или правильную длину пакета, или, очень редко, 4 байта начала тела сообщения.
В сообщении выше дописал про отправку пакетов)) |
Ответ: Непонятки с TCP/IP
Длина текста будет не соответствовать длине пакета.
Хз как блиц, но в более низкого уровня, нужно сперва чётко конвертировать строки в бинарное представление и вычислять длину бинарного массива. Т.к. тот же символ в UTF8 или ASCII уже разных размеров. Также WriteLine будет писать дополнительные данные конца строки. В первом способе, ты не пишешь длину строки (как понимаю блиц сам это вроди делает, что естественно как видишь тебя подводит). Во втором как уже сказал, длина будет не верной из-за возможности использования разных символов. Короче, в пурике всё ок, это блиц тупит. Если есть возможность конвертировать в блице строку в бинарный вид и отправлять массив байтов - делай лучше так. Если есть возможность использовать тот же RakNet - лучше юзай его. |
Ответ: Непонятки с TCP/IP
Все то что ты написал, и про кодировки и про дополнительные символы я учел. Смысл в том что проблема специфическая очень - пропадают именно 4 байта длинны сообщения, все остальное в порядке, и всегда нормально читается.
Есть вариант решения, тупой правда) Отправлять перед телом сообщения не один а два одинавковых integer`a. Даже если один пропадет, второй нормально прочитается, и пакеты после данного не будут потеряны:) |
Ответ: Непонятки с TCP/IP
Теперь я скорее всего догадался в чём проблема:
Блиц возможно применяет собственный алгоритм склеивания сообщений, тем самым если слишком часто отсылать, может клеить стринги вместе. Костыль который предлагаешь - супер изврат.. Короче говоря, лучше возьми либку. |
Ответ: Непонятки с TCP/IP
Насчет склеивания сообщений - вторым методом отправляю integer отдельно, и все равно такая фигня. Кстати тестил и на удаленных соединениях с несколькими клиентами. Точно та же проблема.
Странно все это, ну да ладно:) А костыль изврат, ага, но зато не будет проблемы, и нагрузка от него на сервер и соединение очень незначительные. MoKa, отдельное спасибо за интерес и инфу)) |
Ответ: Непонятки с TCP/IP
Цитата:
|
Ответ: Непонятки с TCP/IP
Пакетный? TCP насколько я помню - непрерывный поток данных, не подразделяющийся на пакеты. Пакетами в данном случае я называю отдельные сообщения в TCP потоке... Как я писал выше оба способа дают одинаковый результат.
|
Ответ: Непонятки с TCP/IP
TCP - это поток данных. Протокол может разбивать данные на сегменты, либо наоборот на уровне протокола в системе ждать пока не будет достаточно данных для полного сегмента (Нагглэ Алгоритм).
Тут дело не с протоколом, а с блицем, и не тем как он кладёт всё в кучу или наоборот, а в том что видимо число порой не отправляется последовательно. Блиц старик, и я бы не юзал стандартный функционал для сети (снова). |
Ответ: Непонятки с TCP/IP
доверяй wireshark-у юный падаван
советы его мудры, око его всевидяще и да прибудет с тобой сила |
Ответ: Непонятки с TCP/IP
Цитата:
Я что-то не очень понял. Разделители типа EOL между строками никуда не денутся. А дейтаграммы и на уровне движка, и на уровне tcp всегда стремятся склеится (лучше отправить 1 раз 500 байт, чем два раза по 250). Функции запроса конкретного типа данных (типа ReadLine) очевидно работают в блокирующем режиме (дожидаясь приёма объекта целиком) с крахом по таймауту, задаваемому функцией TCPTimeouts. тред не читал @ сразу овтечал |
Ответ: Непонятки с TCP/IP
Цитата:
Где гарантия что первый вызов ReceiveNetworkData() запишет в буфер именно 4 байта? А если пришло только, скажем, 2 байта, что тогда? Где гарантия что второй вызов функции, поместить в буфер именно столько байт, сколько указанно в TCPlength? Может на момент чтения еще не все данные пришли, вот и будет выше описанный баг. Если хотите чтобы все работало без сбоев, делайте следующим образом: Заведите буфер, размером в несколько раз больше чем максимальный размер пакета. Читайте данные в этот буфер и анализируйте сколько байт реально было прочитано функцией ReceiveNetworkData(). Если меньше положенного, то ждите и через время опять читайте, помещая результат в конец буфера. Как только приняли все данные, тогда обрабатываете. Буфер очищаете и опять в него пишите принимаемые данные. |
Ответ: Непонятки с TCP/IP
Плин, опять... Как я уже выше писал - еще нет проверки на неполность пакета. Тем не менее, он всегда работает как надо! За последние два месяца это было проверено несколько десятков тысяч раз.
Цитата:
Прежде чем отвечать, внимательно прочитайте предыдущие сообщения в треде. Спасибо. |
Ответ: Непонятки с TCP/IP
Ну смотрите дело ваше.
Я сталкивался с подобным и выше описал как решил проблему. В таком варианте как сейчас, есть вероятность глюков из-за приема не всех данных пакета. |
Ответ: Непонятки с TCP/IP
Кстати, вот один из сценариев пропадания первых 4-ёх байт пакета.
Пакеты отправляются друг за другом и возникает такая ситуация что первые 4 байта нового пакета принимаются с предыдущим пакетом. Как бороться с этим, описал выше. |
Ответ: Непонятки с TCP/IP
это я тоже проверял, пакет принимается ровно столько, сколько нужно - лишнее не захватывает. А вот как 4 байта эти пропадают, тогда уже прога не знает сколько байт считать и получается может захватить последующие пакеты...
|
Ответ: Непонятки с TCP/IP
Цитата:
|
Ответ: Непонятки с TCP/IP
логи отправленных и принятых данных, сравнивал, анализировал;)
Я уже в этом треде раз 5 написал, что код работает абсолютно нормально. Но очень редко и рандомно пропадают именно 4 байта, других ошибок и багов никогда не было. Пётр, извини конечно, но внимательнее читай тему... |
Ответ: Непонятки с TCP/IP
Цитата:
Ну или как альтернатива, гадание на кофейной гуще, раз кода нет. Цитата:
Кому нужно избавится от глюков в проге, мне или тебе? Я тебе уже несколько раз писал чтобы проверял сколько реально было прочитано байт, но видимо ты невнимательно читаешь. |
Ответ: Непонятки с TCP/IP
Код:
PrintN(TCPPacket) Ты мне не веришь что других ошибок не возникало, кроме пропажи integer`а. Ну извини, логи у меня выводятся в консоль, и я их не сохраняю. Предпологалось, что последнее сообщение было на первой странице треда, где я поблагодарил MoKa. Глюков в программе нет, единственное что нужно проверку на неполность сообщения, но это я и сразу знал, и писал об этом. Подправил кстати TCPPacket=PeekS(*TCPBuffer,TCPlength) строчку в коде на первой странице, на прием никак не влияет, но в стринг TCPPacket могут записатся куски старых пакетов из буффера, так как он не очищается... Закрыть бы темку, а то ничего кроме срача тут не предвидится... |
Ответ: Непонятки с TCP/IP
Цитата:
Код:
RealCountBytes_1 = ReceiveNetworkData(TCPclientID,*TCPBuffer,4) Цитата:
Не выйдет из тебя программиста. Нет логического мышления и не слушаешь тех, кто старается тебе помочь! |
Ответ: Непонятки с TCP/IP
Все что я хотел услышать, сказал MoKa. TCPlength тоже логировалось, но раньше, потом убрал за ненадобностью. Когда пропадает те самые 4 байта, тогда TCPlength принимает значение первых 4-х байт тела самого сообщения - а первые 4 байта - символы, то есть если их перевести в integer, получится всегда больше 1000, на что и стояла последующая проверка. Я об этом уже писал.
Ты сталкивался что пропадают конкретные 4 байта сообщения? Причем их нет в предыдущем сообщении, и нет нигде - просто не пришли, как будто их и не отправляли. Это не те случаи, когда пришло еще не все, что должно было, и не те, когда сообщение читается неправильно. Это конкретный, очень специфический случай... На самом деле, в данном случае надо написать кусок клиента на пурике, и посмотреть как он будет себя вести. Ну уж если не выйдет из меня программиста, то все - пойду повешусь на люстре, смысла жизни нет:( п.с. за старание помочь конечно спасибо, но по-моему, мы просто неправильно друг друга понимаем... |
Ответ: Непонятки с TCP/IP
Цитата:
|
Ответ: Непонятки с TCP/IP
Сразу отвечаю, не читаю.
Ты проверяешь длину буффера так? А буффер уже создан давно, и ты лишь записываешь в него прочтённые данные так? Значит длина у него не будет соответствовать на самом деле длине принятых данных. Плюс ты вроди как переиспользуешь буффер для приёма заголовка (4 байта) и затем в него же читаешь само сообщение, так? Получается что в определённом сценарии, при попытки прочитать 4 байта заголовок, ничего не было прочитано, и в буфере будет 4 байта с прошлого буффера сообщения. Если я ничего не упустил - это твоя проблема описана выше. Она заключается в правильной проверке принятых данных и корректной реакции на не соответствия. |
Ответ: Непонятки с TCP/IP
чтение происходит только если новые данные пришли - то есть прошлый буффер, хоть он там и остается, никак не может быть еще раз прочитан, на него хоть один байт, но записывается, и это видно в логах.
еще раз код: Код:
ReceiveNetworkData(TCPclientID, *TCPBuffer,4) То что закоменчено, это как раз было логирование пришедших данных. И в случае ошибки в переменной temp было как раз начало следующего пакета, а должна быть по идее длина пакета - integer. |
Ответ: Непонятки с TCP/IP
Ты считаешь длину буффера а не принятых данных.
Длина принятых данных - это число возвращаемое функцией ReceiveNetworkData. http://www.purebasic.com/documentati...tworkdata.html |
Ответ: Непонятки с TCP/IP
эмм, я тут вообще длину не считаю:) длина принимается от клиента - 4 байта integer...
|
Ответ: Непонятки с TCP/IP
Длина не сообщения, а длина принятых не сервере данных при использовании функции ReceiveNetworkData.
|
Ответ: Непонятки с TCP/IP
Да знаю я что это функция возвращает, хелп читал, примеры других прог смотрел:) но в данном случае эта длина мне не нужна - предпологается что пакеты приходят в одном и том же формате. Следующая после этого функция уже парсит считанные данные - и если они не подходят под формат просто пропускаются. В принципе от нужного клиента данные в другом формате и не приходят, так что тут все пучком))
|
Ответ: Непонятки с TCP/IP
Смотри.
Ты читаешь заголовок 4 байта в буффер. Затем в этот же буффер ты читаешь само сообщение по длине из заголовка. Вроди всё ок. Далее следующий раз читаешь ещё один заголовок 4 байта, и функция ReceiveNetworkData возвращает 0 т.к. по каким-то обстаятельствам не прочла данные, следственно не трогает сам буффер с данными. А ты не проверил это, и сразу переходишь к получению числа из ожидаемых данных заголовка, а это на самом деле прошлые данные (с прошлого сообщения), следственно и длина будет не верная. Так понятнее? С самого начала, я и Пётр говорили именно об этой проверке, не самого буффера с данными, а того сколько принялось данных функцией ReceiveNetworkData. |
Ответ: Непонятки с TCP/IP
Не возвращает она ноль, если она возвратила 0, значит данных нет для чтения. А эта процедура вызывается только если есть данные. Вот так - тут ошибки тоже нет.
Кстати где закоменчено там - вывод в консоль и str и int из этих 4 байт, всегда показывал начало следующего пакета, ни разу предыдущего. |
Часовой пояс GMT +4, время: 08:48. |
vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot