Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TServerSocket, TClientSocket непонятная потеря коннекта


Страницы:   1 2 3

Анонимщик ©   (2004-07-09 16:01:00) 

Клиент подключается к серверу, они обмениваются данными, но только до поры, до времени. Вдруг непонятно из-за чего связь даже не разрывается, но сервер данные шлет успешно, а вот клиент их не принимает, даже не входит в процедуру ClientSocketRead.
К сожалению, более внятно спросить не получается.
В какую сторону нужно смотреть?


Анонимщик   (2004-07-14 18:46:00) [1]

Вполне возможно, что так оно, в конце концов, и будет. Тем более, что это и есть самый правильный метод.


Digitman   (2004-07-14 17:05:00) [2]


> Indy и так создает поток для каждого клиента, еще делать
> и поток для взаимодействия с этим потоком


зачем еще один поток-то создавать на каждое соединение ?

это оправдано лишь в случаях, когда ф-ции транспорта и обработки данных, доставляемых транспортом, требуется по каким-то причинам разнести по разным трэдам

в твоем же случае можно тот самый единственный транспортный трэд, который ассоциирован с клиентом, "научить" кроме трансп.ф-ций "слушать" сообщения, адресованные ему в рамках приложения-сервера

разослать в цикле сообщение всем транспортным тредам вызовом PostThreadMessage() - сущий пустяк, никаких ощутимых временных ресурсов это не займет


Анонимщик   (2004-07-14 16:48:00) [3]

Григорьев Антон ©  

Надо было. Но тогда надо было еще и задуматься, зачем, если Indy и так создает поток для каждого клиента, еще делать и поток для взаимодействия с этим потоком. В общем, я, как обычно, не допер вовремя.


Григорьев Антон   (2004-07-14 16:21:00) [4]

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


Анонимщик   (2004-07-14 11:56:00) [5]

Может, и загнул. А делал следующее: всем заинтересованным в текущих данных клиентам по очереди отсылал одно и то же. Пока сеть локальная, все нормально, как только подключается кто-нибудь через dial-up со своим килобайтом в секунду, так и всем ждать приходится, пока этому клиенту будет отправлена очередная порция данных.


Digitman   (2004-07-14 11:07:00) [6]


> Анонимщик ©   (14.07.04 10:58) [36]



> медленный клиент тормозит всех остальных клиентов и работу
> сервера


что-то ты явно загнул с этим ..

если ты реализовал некорректную/неэффективную логику, то это вовсе не значит, что блокирующий режим есть источник личных твоих бед


Анонимщик   (2004-07-14 10:58:00) [7]

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


Григорьев Антон   (2004-07-14 09:42:00) [8]


> Анонимщик ©   (13.07.04 17:56) [33]


А какая у вас главная цель? Если найти решение проблемы, то, ИМХО, лучше блокирующих сокетов вы ничего не придумаете. А если разобраться с буферизацией, то это не так просто. Я до вчерашнего дня был уверен, что понимаю, как и что, так нет, Digitman новые сведения подкинул, которые противоречат тому, что я раньше читал. Буду дальше рыть MSDN.


Digitman   (2004-07-13 18:45:00) [9]


> использовал для тех же целей Indy, и никаких совершенно
> проблем не было


так ведь этим проблемам в случае блок.режима (каковой использует Инди) и взяться-то неоткуда .... блок.режим подразумевает организацию сет.ядром ЕЩЕ ОДНОГО промежуточного буфера, размер которого ограничен лишь общесистемными ресурсами на момент вызова .. вот в этот промеж.буфер и копируется все то, что ты передал параметрами в send-вызов  ... а уж оттуда порциями по дифолт-размеру ядро последовательно вычерпывает блоки данных и передает их для трансляции


> В локальной сети средняя скорость передачи в случае блокирующего
> режима была почему-то выше, независимо от количества клиентов


как минимум делай скидку на накл.расходы при неблок.режиме ... выигрываешь в удобстве асинхр.режимов - проигрываешь в производительности ... и наоборот ... хотя на сравнительно небольших транслируемых данных (при сравнительно невеликой их интенсивности) это вряд ли заметно ... а если и заметно, то , думаю, оное есть при  использовании оконного механизма асинхр.нотификации о трансп.событиях (см. WSAAsyncSelect)


Анонимщик   (2004-07-13 17:56:00) [10]

Да, насчет блокирующего режима, использовал для тех же целей Indy, и никаких совершенно проблем не было. И еще был один неожиданный и неутешительный для меня момент. В локальной сети средняя скорость передачи в случае блокирующего режима была почему-то выше, независимо от количества клиентов, и даже при использовании только одного компьютера в качестве и сервера, и клиента. Так ничего тогда и не понял.


Digitman   (2004-07-13 17:21:00) [11]


> Кстати, насчёт блокирующего режима


а эт другой огород ...


Григорьев Антон   (2004-07-13 16:51:00) [12]


> Digitman ©   (13.07.04 08:23) [27]
>
> > Григорьев Антон ©   (12.07.04 15:41) [21]


Спасибо за интересную информацию. Как только доберусь до второго компьютера, а также нормального интернета, обязательно проверю. Но даже при беглом обзоре всё выглядит не так однозначно. Вот, например, статья из MSDN'а, в которой прямо указано, что в некоторых случаях в буфер можно положить больше, чем его максимальная длина: http://support.microsoft.com/default.aspx?scid=kb;en-us;214397Правда, там речь только о блокирующем режиме.

Кстати, насчёт блокирующего режима. А может, решить проблему можно как раз его использованием? Тогда не будет никаких WSAEWouldBlock.


Digitman   (2004-07-13 11:25:00) [13]


> приемник получает или слипшиеся, или разделенные куски


абсолютно нормальная ситуация

важно что в конечном итоге приемник рано или поздно получит потокданных именно в том виде и в той последовательности, в какой его сформировал передатчик


> начинаешь делать как проще, а потом - разнообразные грабли


) ... "Закон Черномырдина"


Анонимщик   (2004-07-13 11:10:00) [14]

Спасибо за советы.

Digitman
Кстати, даже на одной машине попытка непрерывно передавать текстовые данные постоянно с помощью SendText в конце концов (и даже довольно быстро, у меня, обычно, и минуты не проходило) приводит к тому, что приемник получает или слипшиеся, или разделенные куски.
А что касается существующих протоколов, то хорошо бы, конечно, но ведь как обычно - начинаешь делать как проще, а потом - разнообразные грабли. Есть, вроде, H231, или что-то такое, но я честно искал описание и реализацию, но ничего дармового так и не нашел. Не исключено, само собой, что плохо искал. Тем более не уверен, что смог бы так просто прикрутить к любому из протоколов нужную мне функциональность, хотя это уже мои предположения.

VID
И тебе спасибо, может, и попробую, если совсем нигде уж более серьезного глюка не найду (есть ведь еще и клиент, его еще в достаточной мере не прологгировал), но у меня есть сомнения к такому способу из-за Анонимщик ©   (12.07.04 14:45) [20]


Digitman   (2004-07-13 08:31:00) [15]


> Григорьев Антон ©   (12.07.04 15:41) [21]


и - обрати внимание - Борланд неспроста использует в теле метода SensStreamPiece() промежуточную буферизацию блоками по 4к ... кратность размера буфера размеру страницы вирт.памяти бесспорно никогда не помешает, а дифолтные 8к делятся как раз пополам ..


Digitman   (2004-07-13 08:23:00) [16]


> Григорьев Антон ©   (12.07.04 15:41) [21]


однако на тот самый дифолт в 8к многие и "попадают" неожиданно..
ты же сам видишь - сплошь и рядом в "Сетях" вопросы а-ля   почему, мол, получается так, что я косой десяток раз подряд вызывал SendText, отправив в общей сложности строк килобайт эдак на 200, а на стороне приемника получил всего лишь одно событие OnRead, где ReceiveLength показал мне что-то около 8к...

когда и приемник и передатчик находятся на одной машине, то этот дифолт как правило не заметен - можно и сотню-другую кб отправить к ряду одним send-вызовом и при этом не получить wsaewouldblok .. ядро эффективно разруливает такую localhost-ситуацию.. но стоит только разнести приемник и передатчик в глоб.сети, как дифолт этот встает во весь рост


> Анонимщик ©   (12.07.04 14:32) [19]


ну что тебе здесь можно посоветовать ?
во-первых присмотреться внимательно к существующим на сей день real-media-протоколам и кодекам, формирующим поток медиаданных для трансляции по тому или иному трансп.протоколу (в твоем случае - TCP/IP)

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


VID   (2004-07-13 00:39:00) [17]

TO: Анонимщик
Если не хочешь использовать событие OnWrite, то можешь использовать функцию WaitForData (совсем немного переделана мною):

function WaitForData(Socket:TSocket; Timeout: Longint; IsWriteMode:Boolean): Boolean;
var
 FDSet: TFDSet;
 TimeVal: TTimeVal;
begin
 TimeVal.tv_sec := Timeout div 1000;
 TimeVal.tv_usec := (Timeout mod 1000) * 1000;
 FD_ZERO(FDSet);
 FD_SET(Socket, FDSet);
 IF IsWriteMode then
   Result := select(0, nil, @FDSet, nil, @TimeVal) > 0
 else Result := select(0, @FDSet, nil, nil, @TimeVal) > 0
end;


Эту функцию используем так: Перед каждым вызовом SendBuf сначала проверяем, способен ли сокет принять данные, для размещения их в очередь на отправку. Вот, смотри:


     IF WaitForData(FSocket.SocketHandle, 1000, True) then
     begin
       ...
         SendSize := TargetSocketThread.FSocket.SendBuf((@Text[Result+1])^, RemainSize);
       ...
     end else begin {действия если НЕ СПОСОБЕН} end;


Причём, если тебе необходимо во-что бы то ни стало дождаться, и отправить данные, то весь вышеуказанный код примера надо поместить в цикл, где и будет проверяться то, сколько байт отправлено (отправлено = общий размен, то выходим из цикла).
Учти, что в этом случае, твой поток станет глухим и слепым, он зациклится, пока цикл не выполниться. Совет: при второй итерации цикла, вызывай Sleep(1).
Это можно сделать, например, так:

firstiteration := true;
repeat
 if firstiteration then firstiteration := false else sleep(1);
until....


В-общем, попробуй это решение, и может твой вопрос в Анонимщик ©   (12.07.04 14:45) [20] потеряет актуальность.


Polevi   (2004-07-12 18:22:00) [18]

организуй свою очередь, помещай данные в нее а затем вызывай некую ф-ию F которая будет пытаться отправить очередь до тех пор пока все не отправит, либо до WSA_EWOULDBLOCK
в обработчике OnWrite просто вызывай F ф-ию


Анонимщик   (2004-07-12 16:58:00) [19]

Я вот чем дальше тестирую, тем реже появляется ошибка. А всего-то вставил после SendBuf():
lastErr := GetLastError;
if lastErr <> 0 then begin
Writeln(fLog, IntToStr(lastErr));
Flush(fLog);
end;

Опять-таки, непонятно почему. Условия вроде как одинаковые.
Но снова хочу повторить [20]:

Ну вот, интересно, я под дебагом поставил условия, чтобы из цикла программа вываливалась, потом, через какое-то время (пару минут), чтобы снова начиналась передача данных. Тот же эффект, SendBuf() возвращает -1. Сеть локальная, передаю себе же, на свой же компьютер, т.е. за две минуты все, что там накопилось, ну точно должно отправится. С чем такое поведение может быть связано?

Конечно, логику работы исправлю, но этот момент все же непонятен.


Григорьев Антон   (2004-07-12 16:51:00) [20]


> Так что я не понял, с чем не согласен?


Я не согласен вот с этой фразой:

>  Если хочешь узнать размер по дифолту внутреннего буфера
> передачи, на то есть ф-ция GetSockOpt() с соотв. константой-параметром
> ... больше данных чем этот размер ты все равно не сможешь
> "затолкать" в очередь передачи


Затолкать больше вполне реально, т.к. максимальный размер заталкиваемого определяется низкоуровневым буфером, а GetSockOpt даёт размер высокоуровнего. Проверено практикой: через сокет можно отправлять пакеты большего размера, чем тот, который определяется через GetSockOpt.

Но это не значит, что предела нет, он есть, но через GetSockOpt его не узнаешь.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо