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

Вниз

Как узнать сколько байт собирается мне (клиенту) передать сервер   Найти похожие ветки 

 
sunsay   (2005-07-04 17:14) [0]

Привет всем мастерам!

У меня есть один вопрос, ответ на который я так и не смог нигде найти (видимо плохо искал):
Есть блокирующий TClientSocket, есть следующая функция получения данных из сокета:

//-------------------------------------------------------------------------------//
// Функция получения данных из сокета                                            //
//-------------------------------------------------------------------------------//
function TCustomMailSocket.RecieveData: String;
var
 RequestPChar: PChar;
 BytesRead: Integer;
begin
 ...
 GetMem(RequestPChar, 1024);
 while (FSocket.Socket.ReceiveLength > 0) then begin
   ...
   BytesRead := FStream.Read(RequestPChar^, 1024); // читаем данные из сокета
   ...
 end;
 FreeMem(RequestPChar, 1024);
 ...
end;

У меня вопрос, соответственно:
Как можно узнать сколько байт данных от сервера передано мне в сокет и собирается ли сервер слать ещё
или, например, узнать сколько вообще байт собирается мне переслать сервер...
потому что у меня возникали случаи, когда при асинхронном режиме метод OnClientRead вызывался несколько раз при
передаче больших объемов данных по сети.

P.S. ReceiveLength, как я понимаю, возвращает размер информации, уже находящейся в
сокете, но не факт, что это вся информация, которую пересылает мне сервер...


 
simpson ©   (2005-07-04 17:33) [1]

When ClientType is ctBlocking, use a TWinSocketStream object for reading and writing.

На мысли не наводит?


 
Digitman ©   (2005-07-04 17:34) [2]


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


а BytesRead - это для кого ?


> собирается ли сервер слать ещё


ответ на вопрос дает конкретный протокол инф.обмена


> ReceiveLength, как я понимаю, возвращает размер информации,
> уже находящейся в
> сокете


неправильно понимаешь.


> не факт, что это вся информация, которую пересылает мне
> сервер


правильно понимаешь.


 
simpson ©   (2005-07-04 17:38) [3]

Для определения количества байт, уже принятых твоим сокетом от сервера, используй пару методов: TWinSocketStream.WaitForData и TStream.Read

Кроме того, протокол обмена между клиентом и сервером должен быть известен (в нормальной ситуации). Следовательно, у тебя уже есть ответ на вопрос "сколько вообще байт собирается мне переслать сервер" - это определяется протоколом обмена.

Данные при большом их объеме, ессно, будут приходить частями.


 
sunsay   (2005-07-04 18:14) [4]

2simpson:
FStream и есть TWinSocketStream

2Digitman:
> а BytesRead - это для кого ?
логично... загнался я немного.

2All:
Вообще, я соединяюсь с почтовым сервером по POP3 (RFC 1081).
В принципе всё работает и через всякие там FSocket.ReceiveText, но хочется чего-то более надежного с точки зрения устойчивости к обрывам связи, так как для FStream (TWinSocketStream) можно задать тайм-аут на чтение при создании. Но... чтение почты происходит, как Вы понимаете, в отдельном потоке и представим ситуацию, что пользователь закрывает мою программу, а мой поток висит по FStream.WaitForData - так вот желания его (поток) просто "рубить" у меня нету - хочется чего-то нежно и красиво завершающегося...

Кстати в FStream.Read тоже вешает поток, если данных нет в сокете, а программу мою уже закрыли - но это я обошел вместо WaitForSingleObject(Handle, FTimeOut) сделал
WaitForMultipleObjects и акромя таймаута добавил что-то типа TerminationEvent в коде метода TWinSocketStream.Read;
Но вот с WaitForData так не получится - так как там вызывается select:


function TWinSocketStream.WaitForData(Timeout: Longint): 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(FSocket.SocketHandle, FDSet);
 Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;


 
Digitman ©   (2005-07-04 18:21) [5]


> Вообще, я соединяюсь с почтовым сервером по POP3


на здоровье.
хоть по ЖОП33) .. stream-oriented connection от этого никак не пострадало и никак не зависит от прикл.протокола, коим всяки-разны POP/ЖОП являются


 
simpson ©   (2005-07-04 18:57) [6]

> Но... чтение почты происходит, как Вы понимаете, в отдельном
> потоке и представим ситуацию, что пользователь закрывает мою
> программу, а мой поток висит по FStream.WaitForData

Висеть он будет ровно столько, сколько ты укажешь при вызове WaitForData.


       if Stream.WaitForData(60000) then  

       begin
         if Stream.Read(Buffer, 10) = 0 then { if can’t read in 60 seconds }
           ClientSocket.Close;               { close the connection }
         { now process the request }
         ...
       end
       else
         ClientSocket.Close; { if client doesn’t start, close }


Вот здесь он будет висеть ровно минуту, если нет данных.

> Вообще, я соединяюсь с почтовым сервером по POP3 (RFC 1081)

Тогда что за вопрос, сколько данных еще собирается прислать сервер? Все написано в указанном RFC.

> хочется чего-то нежно и красиво завершающегося...

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


 
sunsay   (2005-07-04 21:17) [7]

ОК, всем спасибо, в принципе разобрался...
Хотя ReceiveLength не совсем понятно чем занимается, может кто переведет:
Description
Call ReceiveLength to determine the amount of information to read over the socket connection in response to an asynchronous read notification.

Note: ReceiveLength is not guaranteed to be accurate for streaming socket connections.

<Digitman> сказал, что я вроде как перевел неправильно, сказав, что "ReceiveLength используется для получения количества информации, доступной для чтения в сокете"


 
simpson ©   (2005-07-04 23:18) [8]

К сожалению, ты упорно путаешь блокирующий (он же синхронный) режим работы сокетов, и неблокирующий (асинхронный).

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

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

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


procedure TMyThread.Execute;
var
 Stream: TWinSocketStream;
begin
 // установка соединения...
 ...
 FSocket.Open;
 ...
 try
   while (not Terminated) and FSocket.Connected do
     begin
       Stream := TWinSocketStream.Create(...);
       try
         if Stream.WaitForData(...) then
           begin
             // реализация протокола обмена
             // последовательные вызовы Stream.Read,
             // Stream.Write
           end
         else
           FSocket.Close;
       finally
         Stream.Free;
       end;
     end;
 finally
   // дисконнект от сервера
   FSocket.Close;
 end;
end;


Т. е. подключились, создали сокетный поток, подождали даные, прочитали, записали, повторили нужное количество раз чтение/запись, уничтожили поток, отключились.

Синхронный режим. Вопрос-ответ, и так несколько этапов в зависимости от протокола.



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

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

Наверх




Память: 0.48 MB
Время: 0.041 c
1-1127972935
Mixer
2005-09-29 09:48
2005.10.23
Balloon Tips &amp; Windows XP


2-1127907181
Гость22
2005-09-28 15:33
2005.10.23
Как не дать закрыть свое приложение?


2-1124833887
ronyn
2005-08-24 01:51
2005.10.23
Как создать программку ТРЕЙ?


14-1128068917
Igorek
2005-09-30 12:28
2005.10.23
А что Вы знаете о Гондурасе?


4-1124286067
Anatoly
2005-08-17 17:41
2005.10.23
Функции BitBtl, StretchBLT дают пустую страницу на принтере





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский