Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.23;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.027 c
14-1127820439
VictorT
2005-09-27 15:27
2005.10.23
Подкиньте плиз ссылок на описание Pagemaker tagged text


6-1120190873
NorthMan
2005-07-01 08:07
2005.10.23
Про Indy и синхронизацию потоков


14-1127992402
alk20
2005-09-29 15:13
2005.10.23
Помогите программа не работает так как надо из под win 98


3-1126268799
alsov
2005-09-09 16:26
2005.10.23
Подскажите функция, которая из значения null делает заданый текст


14-1127997108
oldman
2005-09-29 16:31
2005.10.23
Я таки победил 1C!!!