![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TServerSocket, TClientSocket непонятная потеря коннекта
Анонимщик © (2004-07-09 16:01:00)Клиент подключается к серверу, они обмениваются данными, но только до поры, до времени. Вдруг непонятно из-за чего связь даже не разрывается, но сервер данные шлет успешно, а вот клиент их не принимает, даже не входит в процедуру ClientSocketRead.
К сожалению, более внятно спросить не получается.
В какую сторону нужно смотреть?
Анонимщик (2004-07-12 16:06:00) [21]Григорьев Антон © (12.07.04 15:41) [21]
Digitman именно об этом "высокоуровневом" буфере и писал. Я его выставляю в 32 кб, но это неважно. Тем более, что, если я правильно понял, на самом деле это все системе до фени, она при случае может его "поправить", никого об этом не извещая. Для ускорения - может быть, но только не в том случае, когда данные все валят и валят.
Так что я не понял, с чем не согласен?
Григорьев Антон (2004-07-12 15:41:00) [22]
> Digitman © (12.07.04 14:27) [17]
>
> 1. Зачем тебе это надо ? Не надо оно тебе ... Если хочешь
> узнать размер по дифолту внутреннего буфера передачи, на
> то есть ф-ция GetSockOpt() с соотв. константой-параметром
> ... больше данных чем этот размер ты все равно не сможешь
> "затолкать" в очередь передачи
Не согласен. Есть два буфера - высокоуровневый и низкоуровневый. Высокоуровневый нужен только для ускорения работы. Он имеет фиксированный размер. По умолчанию 8192 байта. Он имеет постоянный размер и служит чем-то вроде кеша для низкоуровнего. Про низкоуровневый буфер я такой точной информации не нашёл, но, как я понял, его размер динамически меняется в некоторых пределах. Объём отправляемой информации определяется именно этими пределами, а изменение размера высокоуровнего буфера влияет только на скорость работы. Так, например, при размере буфера 8192 можно без проблем отправлять пакеты размером около 64 кб, и всё работает - проверено. В MSDN'е написано, что размер высокоуровнего буфера можно уменьшить аж до нуля - на функциональности это никак не скажется, только на скорости. И Get(Set)SockOpt работают именно с высокоуровневым буфером, а как узнать размер низкоуровнего - я и сам хотел бы знать.
Анонимщик (2004-07-12 14:45:00) [23]Ну вот, интересно, я под дебагом поставил условия, чтобы из цикла программа вываливалась, потом, через какое-то время (пару минут), чтобы снова начиналась передача данных. Тот же эффект, SendBuf() возвращает -1. Сеть локальная, передаю себе же, на свой же компьютер, т.е. за две минуты все, что там накопилось, ну точно должно отправится. С чем такое поведение может быть связано?
Анонимщик (2004-07-12 14:32:00) [24]2. Ну, окончание не совсем верное.
Да, а что? Правда, сети не совсем глобальная, а данные сжатые.
Digitman (2004-07-12 14:29:00) [25]
> Анонимщик
ты там случаем не видеоданные ли пытаешься толкать по глоб.сети в реальном режиме времени ?
Digitman (2004-07-12 14:27:00) [26]
> Анонимщик © (12.07.04 14:10) [16]
1. Зачем тебе это надо ? Не надо оно тебе ... Если хочешь узнать размер по дифолту внутреннего буфера передачи, на то есть ф-ция GetSockOpt() с соотв. константой-параметром ... больше данных чем этот размер ты все равно не сможешь "затолкать" в очередь передачи
2. Даже если ты получил в ответ не -1, а то что ожидал (т.е. размер данных, который ты передал в SendBuf), ты невправе ожидать. что эти данные будут физически доставлены приемнику еще ДО того момента, как ты будешь вызывать очередной SendBuf ... толку от SendBuF() > 0 - никакого .. в момент физической доставки приемнику фрагмента (о размере принятого фрагмента ты тоже не вправе судить - он может быть произвольным) актуальность того, что только что доставлено приемнику, уже может, по твоей логике, утратить силу
Анонимщик (2004-07-12 14:10:00) [27]Понятно, но все же мне это не очень нравится. Хочу еще спросить:
1. Можно ли и как узнать, сколько байт приемный буфер еще в состоянии гарантированно принять?
2. Есть ли какие-нибудь рекомендации, как обойти тот случай, когда часть данных передано, а дальше - SendBuf() возвращает -1. Не хочется заниматься временными данными, уже потерявшими актуальность. Или без этого, в конце концов, не обойтись?
Digitman (2004-07-12 13:55:00) [28]
> Анонимщик © (12.07.04 13:52) [14]
> я своим циклом не даю этой возможности?
конечно !
ядро тебе сообщило возвратом -1 о том, что очередь передачи заполнена ... бессмысленно пытаться вновь и вновь толкать туда данные ... дождись OnWrite и продолжи формирование очереди с того места, с которого ты получил отказ
Анонимщик (2004-07-12 13:52:00) [29]Да, совершенно верно, именно -1.
И совет будет способен снова передавать данные только после возникновения события OnWrite, верно? А я своим циклом не даю этой возможности?
Verg (2004-07-12 13:23:00) [30]
> [12] Анонимщик © (12.07.04 13:08)
> Verg
>
> Кстати, send() возвращает именно 0, а не -1. Несколько не
> вяжется с твоим объяснением.
Оно не может "не вязаться", потому что так есть на самом деле. Это не догадки или предположения - это факты.
Буть внимательнее.
Если 0 - разрыв соединения, если -1 (SOCKET_ERROR или $FFFFFFFF) , то см. WSAGetLastError, если >0, то это столько байтов из предложенных тобой ядро поместило в буфер передачи сокета.
Анонимщик (2004-07-12 13:08:00) [31]Verg
Кстати, send() возвращает именно 0, а не -1. Несколько не вяжется с твоим объяснением.
Verg (2004-07-12 13:04:00) [32]WSAEWOULDBLOCK (ошибка №10035) - означает, что сетевое ядро не может в данный момент принять ВООБЩЕ НИ ОДНОГО БАЙТА для передачи по данному сокету. Это вообще-то не ошибка (не фатальная ошибка). Исторически принято, что если ф-ция send вернула в результате 0 байтов, то это означает разрыв соединения. Т.о., если сокет работает в неблокирующем режиме, то запросто может сложиться ситуация, что передающий буфер сокета оказался полностью заполнен, а вернуть 0 в результате send - будет неверно истолковано приложением. Вот и выдумали errno = EWOULDBLOCK, а send() return SOCKET_ERROR,т.е. -1.
> А чем он может быть занят?
Передачей информации. Сеть, много компов в ней, скорость передачи, конфликты, маршрутизаторы, неторопливость адресата и проч. разные неприятности...
Из одного конца города в другой теоритически можно добраться со ср. скоростью = MAX_SPEED_OF_YOUR_CAR км/ч, но так получается только по ночам и только в голлвивудских фильмах. Почему?
Если средняя скорость извлечения инф. из буфера меньше, чем ср. скорость пополнения этого буфера, то рано или поздно наступит момент, когда буфер окажется заполненным полностью, при том, (если не брать в расчет специальные случаи, когда, например, размер буфера превосходит суммарный объем передаваемой и-ции за соединение) вне зависимости от размера этого буфера.
Анонимщик (2004-07-12 12:58:00) [33]Спасибо.
Я имел в виду "отмену" - как учитывание в моем протоколе, что, мол, не обрабатывать данные (на клиентской стороне) до прихода специальной команды.
Я хочу или полностью отправить все данные, или, если это невозможно, не отправлять их вовсе.
Код такой:
fullSend := 0;
while fullSend < SizeOf(writeBufferSendSize) do
begin
tmpSend := FServerSocket.Socket.Connections[j].SendBuf(Pointer(Integer(@writeBufferSendSize) + fullSend)^, SizeOf(writeBufferSendSize) - fullSend);
if tmpSend >= 0 then fullSend := fullSend + tmpSend
else begin
if fullSend = 0 then break;
end
else break; // что делать здесь, если чаcть данных уже послана?
end;
Т.е. я хочу или полностью отправить все данные или, если самая первая попытка была неуспешна (SendBuf выдал 0 или -1), то отказываюсь вовсе от передачи данных. Но что делать, когда часть данных отправлена, а часть - нет? Я согласен бы и подождать, но получается так, что код постоянно крутится в цикле while.
Вы говорите, что нужно обязательно ждать события OnWrite? Но тогда придется ставить флажки и использовать временные буфера. Можно как-то элегантнее реализовать? Есть еще какие-то возможности?
Григорьев Антон (2004-07-12 12:41:00) [34]
> Анонимщик © (12.07.04 12:22) [7]
> Digitman
>
> А чем он может быть занят? С многопоточностью это свящано?
Send кладёт данные в буфер сокета, а потом они отправляются получателю в фоновом режиме. Если данные кладутся слишком быстро, то отправляться они не успевают, и буфер переполняется. С многопоточностью это не связано.
Digitman (2004-07-12 12:40:00) [35]
> Анонимщик © (12.07.04 12:22) [7]
скорость физическойпередачи данных (тех самых что поставлены тобой в очередь на передачу одним или несколькими последовательными вызовами send-методов) зависит от множества факторов, на которые ты программно повлиять не можешь (например, пропускная способность сети).. как ты ни пыжься, а TCP/IP- пакеты будут передаваться и приниматься (TCP протокол подразумевает квитирование доставляемых пакетов, это гарантирует их доставку) строго с той скоростью, которая возможна в дан.момент времени..
по мере гарантированно успешной физ.передачи очередного фрагмента поточных данных внутр.очередь (та самая, в хвост которой ты фактически ведешь запись вызовами sendbuf) освобождается на величину физически переданного фрагмента
то что твои данные, требуемые к передаче, теряют актуальность быстрей физ.передачи - это твоя проблема, ты ОБЯЗАН учитывать этот фактор
> пересылку старых отменить как-то
"пересылку" ты отменить не можешь - данные уже помещены в хвост очереди передачи (являющей собой поток, в котором уже нет никакой возможности разделить отдельно записанные тобой фрагменты) и ждут своей очередности на физ.передачу... отмена передачи - это отмена всего потока передачи, которую можно осуществить только закрытием соединения
Анонимщик (2004-07-12 12:22:00) [36]Digitman
А чем он может быть занят? С многопоточностью это свящано?
Дело в том, что что мне проще отказаться вообще от посылки этого пакета, по частям пересылать плохо - данные постоянно меняются, и, если ждать события, то данные устареют и нужно будет пересылать уже новые, а пересылку старых отменить как-то. Словом, некрасиво выходит.
Можно как-то узнать, например, сколько буфер в состоянии принять в данный момент?
Григорьев Антон (2004-07-12 12:18:00) [37]Да, большой объём данных приходится пересылать, если такая ошибка вылезла.
После такой ошибки надо ждать, когда возникнет OnSocketEvent с seWrite и только после этого возобновлять отправку данных.
Lock/Unlock к блокирующему и неблокирующему режиму работы сокета отношения не имеет.
Digitman (2004-07-12 12:15:00) [38]
> Анонимщик © (12.07.04 11:58) [4]
> Ошибка номер 10035: операция на незаблокированном сокете
> не может быть завершена немедленно.
ошибка 10035 означает, что внутренний буфер передачи занят и не может вместить (поставить к хвост очереди на передачу) тот целыйобъем данных, который ты затребовал в SendBuf()
дождись события On[Client]Write и в его обработчике повтори попытку отправки тех же самых данных, при предыдущей попытке отправки которых ты получил код отказа 10035
Анонимщик (2004-07-12 11:58:00) [39]Ну вот, ошибка возникает (точнее, не возникает, но ее можно получить через GetLastError) при
FServerSocket.Socket.Connections[j].SendBuf(...)
Ошибка номер 10035: операция на незаблокированном сокете не может быть завершена немедленно.
Почитал в справке о TCustomWinSocket.Lock/Unlock, но чего-то не все понял. Можете рассказать об этом?
Verg (2004-07-12 09:43:00) [40]Например.
Проверь, что на каждое событие OnRead код обязательно вызывает recv (receivebuffer, receivetext... или т.п.) на этом сокете.