Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2004.09.19;
Скачать: [xml.tar.bz2];

Вниз

TServerSocket, TClientSocket непонятная потеря коннекта   Найти похожие ветки 

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

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


 
Digitman ©   (2004-07-09 16:36) [1]

в сторону отладчика


 
Анонимщик ©   (2004-07-09 17:54) [2]

Ладно, спасибо.


 
Verg ©   (2004-07-12 09:43) [3]

Например.
Проверь, что на каждое событие OnRead код обязательно вызывает recv (receivebuffer, receivetext... или т.п.) на этом сокете.


 
Анонимщик ©   (2004-07-12 11:58) [4]

Ну вот, ошибка возникает (точнее, не возникает, но ее можно получить через GetLastError) при
FServerSocket.Socket.Connections[j].SendBuf(...)

Ошибка номер 10035: операция на незаблокированном сокете не может быть завершена немедленно.

Почитал в справке о TCustomWinSocket.Lock/Unlock, но чего-то не все понял. Можете рассказать об этом?


 
Digitman ©   (2004-07-12 12:15) [5]


> Анонимщик ©   (12.07.04 11:58) [4]


> Ошибка номер 10035: операция на незаблокированном сокете
> не может быть завершена немедленно.


ошибка 10035 означает, что внутренний буфер передачи занят и не может вместить (поставить к хвост очереди на передачу) тот целый объем данных, который ты затребовал в SendBuf()

дождись события On[Client]Write и в его обработчике повтори попытку отправки тех же самых данных, при предыдущей попытке отправки которых ты получил код отказа 10035


 
Григорьев Антон ©   (2004-07-12 12:18) [6]

Да, большой объём данных приходится пересылать, если такая ошибка вылезла.

После такой ошибки надо ждать, когда возникнет OnSocketEvent с seWrite и только после этого возобновлять отправку данных.

Lock/Unlock к блокирующему и неблокирующему режиму работы сокета отношения не имеет.


 
Анонимщик ©   (2004-07-12 12:22) [7]

Digitman

А чем он может быть занят? С многопоточностью это свящано?
Дело в том, что что мне проще отказаться вообще от посылки этого пакета, по частям пересылать плохо - данные постоянно меняются, и, если ждать события, то данные устареют и нужно будет пересылать уже новые, а пересылку старых отменить как-то. Словом, некрасиво выходит.
Можно как-то узнать, например, сколько буфер в состоянии принять в данный момент?


 
Digitman ©   (2004-07-12 12:40) [8]


> Анонимщик ©   (12.07.04 12:22) [7]


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

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

то что твои данные, требуемые к передаче, теряют актуальность быстрей физ.передачи  - это твоя проблема, ты ОБЯЗАН учитывать этот фактор


>  пересылку старых отменить как-то


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


 
Григорьев Антон ©   (2004-07-12 12:41) [9]


> Анонимщик ©   (12.07.04 12:22) [7]
> Digitman
>
> А чем он может быть занят? С многопоточностью это свящано?


Send кладёт данные в буфер сокета, а потом они отправляются получателю в фоновом режиме. Если данные кладутся слишком быстро, то отправляться они не успевают, и буфер переполняется. С многопоточностью это не связано.


 
Анонимщик ©   (2004-07-12 12:58) [10]

Спасибо.
Я имел в виду "отмену" - как учитывание в моем протоколе, что, мол, не обрабатывать данные (на клиентской стороне) до прихода специальной команды.

Я хочу или полностью отправить все данные, или, если это невозможно, не отправлять их вовсе.
Код такой:

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? Но тогда придется ставить флажки и использовать временные буфера. Можно как-то элегантнее реализовать? Есть еще какие-то возможности?


 
Verg ©   (2004-07-12 13:04) [11]

WSAEWOULDBLOCK (ошибка №10035) - означает, что сетевое ядро не может в данный момент принять ВООБЩЕ НИ ОДНОГО БАЙТА для передачи по данному сокету. Это вообще-то не ошибка (не фатальная ошибка). Исторически принято, что если ф-ция send вернула в результате 0 байтов, то это означает разрыв соединения. Т.о., если сокет работает в неблокирующем режиме, то запросто может сложиться ситуация, что передающий буфер сокета оказался полностью заполнен, а вернуть 0 в результате send - будет неверно истолковано приложением. Вот и выдумали errno = EWOULDBLOCK, а send() return SOCKET_ERROR,т.е. -1.


> А чем он может быть занят?


Передачей информации. Сеть, много компов в ней, скорость передачи, конфликты, маршрутизаторы, неторопливость адресата и проч. разные неприятности...
Из одного конца города в другой теоритически можно добраться со ср. скоростью = MAX_SPEED_OF_YOUR_CAR км/ч, но так получается только по ночам и только в голлвивудских фильмах. Почему?

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


 
Анонимщик ©   (2004-07-12 13:08) [12]

Verg

Кстати, send() возвращает именно 0, а не -1. Несколько не вяжется с твоим объяснением.


 
Verg ©   (2004-07-12 13:23) [13]


> [12] Анонимщик ©   (12.07.04 13:08)
> Verg
>
> Кстати, send() возвращает именно 0, а не -1. Несколько не
> вяжется с твоим объяснением.


Оно не может "не вязаться", потому что так есть на самом деле. Это не догадки или предположения - это факты.
Буть внимательнее.

Если 0 - разрыв соединения, если -1 (SOCKET_ERROR или $FFFFFFFF) , то см. WSAGetLastError, если >0, то это столько байтов из предложенных тобой ядро поместило в буфер передачи сокета.


 
Анонимщик ©   (2004-07-12 13:52) [14]

Да, совершенно верно, именно -1.
И совет будет способен снова передавать данные только после возникновения события OnWrite, верно? А я своим циклом не даю этой возможности?


 
Digitman ©   (2004-07-12 13:55) [15]


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


> я своим циклом не даю этой возможности?


конечно !
ядро тебе сообщило возвратом -1 о том, что очередь передачи заполнена ... бессмысленно пытаться вновь и вновь толкать туда данные ... дождись OnWrite и продолжи формирование очереди с того места, с которого ты получил отказ


 
Анонимщик ©   (2004-07-12 14:10) [16]

Понятно, но все же мне это не очень нравится. Хочу еще спросить:
1. Можно ли и как узнать, сколько байт приемный буфер еще в состоянии гарантированно принять?
2. Есть ли какие-нибудь рекомендации, как обойти тот случай, когда часть данных передано, а дальше - SendBuf() возвращает -1. Не хочется заниматься временными данными, уже потерявшими актуальность. Или без этого, в конце концов, не обойтись?


 
Digitman ©   (2004-07-12 14:27) [17]


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


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

2. Даже если ты получил в ответ не -1, а то что ожидал (т.е. размер данных, который ты передал в SendBuf), ты невправе ожидать. что эти данные будут физически доставлены приемнику еще ДО того момента, как ты будешь вызывать очередной SendBuf ... толку от SendBuF() > 0 - никакого .. в момент физической доставки приемнику фрагмента (о размере принятого фрагмента ты тоже не вправе судить - он может быть произвольным) актуальность того, что только что доставлено приемнику, уже может, по твоей логике, утратить силу


 
Digitman ©   (2004-07-12 14:29) [18]


> Анонимщик


ты там случаем не видеоданные ли пытаешься толкать по глоб.сети в реальном режиме времени ?


 
Анонимщик ©   (2004-07-12 14:32) [19]

2. Ну, окончание не совсем верное.

Да, а что? Правда, сети не совсем глобальная, а данные сжатые.


 
Анонимщик ©   (2004-07-12 14:45) [20]

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


 
Григорьев Антон ©   (2004-07-12 15:41) [21]


> Digitman ©   (12.07.04 14:27) [17]
>
> 1. Зачем тебе это надо ? Не надо оно тебе ... Если хочешь
> узнать размер по дифолту внутреннего буфера передачи, на
> то есть ф-ция GetSockOpt() с соотв. константой-параметром
> ... больше данных чем этот размер ты все равно не сможешь
> "затолкать" в очередь передачи


Не согласен. Есть два буфера - высокоуровневый и низкоуровневый. Высокоуровневый нужен только для ускорения работы. Он имеет фиксированный размер. По умолчанию 8192 байта. Он имеет постоянный размер и служит чем-то вроде кеша для низкоуровнего. Про низкоуровневый буфер я такой точной информации не нашёл, но, как я понял, его размер динамически меняется в некоторых пределах. Объём отправляемой информации определяется именно этими пределами, а изменение размера высокоуровнего буфера влияет только на скорость работы. Так, например, при размере буфера 8192 можно без проблем отправлять пакеты размером около 64 кб, и всё работает - проверено. В MSDN"е написано, что размер высокоуровнего буфера можно уменьшить аж до нуля - на функциональности это никак не скажется, только на скорости. И Get(Set)SockOpt работают именно с высокоуровневым буфером, а как узнать размер низкоуровнего - я и сам хотел бы знать.


 
Анонимщик ©   (2004-07-12 16:06) [22]

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

Digitman именно об этом "высокоуровневом" буфере и писал. Я его выставляю в 32 кб, но это неважно. Тем более, что, если я правильно понял, на самом деле это все системе до фени, она при случае может его "поправить", никого об этом не извещая. Для ускорения - может быть, но только не в том случае, когда данные все валят и валят.
Так что я не понял, с чем не согласен?


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


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


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

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


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

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


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

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

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

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

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


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

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


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

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] потеряет актуальность.


 
Digitman ©   (2004-07-13 08:23) [27]


> Григорьев Антон ©   (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)

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


 
Digitman ©   (2004-07-13 08:31) [28]


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


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


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

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

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

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


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


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


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

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


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


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


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


> 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 17:21) [32]


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


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


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

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


 
Digitman ©   (2004-07-13 18:45) [34]


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


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


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


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


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


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


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


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

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


 
Digitman ©   (2004-07-14 11:07) [37]


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



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


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

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


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

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


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

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


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

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

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


 
Digitman ©   (2004-07-14 17:05) [41]


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


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

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

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

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


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

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



Страницы: 1 2 вся ветка

Форум: "Сети";
Текущий архив: 2004.09.19;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.6 MB
Время: 0.037 c
1-1094124337
demonyator
2004-09-02 15:25
2004.09.19
Acdsee


10-1034651971
Comwad
2002-10-15 07:19
2004.09.19
Глюк в Delphi 7 или VB4.5 (Пример Midas XML)


14-1093779014
olookin
2004-08-29 15:30
2004.09.19
Завтра стартует Кубок Мира по хоккею...


14-1093524695
hgd
2004-08-26 16:51
2004.09.19
Помогите с установка компонента


14-1093842147
Vlad Oshin
2004-08-30 09:02
2004.09.19
Не корректная печать отчетов FastReport





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский