Форум: "Сети";
Текущий архив: 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.039 c