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

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

Не возвращается количество полученных байт в блокирующисокетах??? [D6, Win2k]


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

slgeo ©   (2004-03-19 10:04:00) 

У меня идет обмен по блокирующим сокетам, а точнее передача файла от
серверного потока клиентскому:
на клиенте срабатывает следующий код
   var
    Buf : string;
   
   if Stream.WaitForData(40000) then
     begin
       SetLength(Buf, 18);
       nRead := Stream.Read(Buf[1], 18);
   ...
   end;
   
    Так вот на некоторых машинах, точнее на 2-х из 5-ти, в nRead
    возвращается 0! Но данные на самом деле передаются! На этих 2-х
    установлена Win98 SE, на остальных 3-х машинах, где в nRead
    возвращается количество принятых байт:
    1 - WinXP
    2 - WinXP
    3 - Win98 SE

   Я уже не знаю где искать, замена файлов
   winsock.dll,wsock32.dll,wininet.dll ни к чему не приводит.


Digitman   (2004-03-19 11:18:00) [41]


> Verg ©   (19.03.04 10:55) [12]


нет, ну насчет того, что Read() сам по себе блокирующий, я согласен на все 100 ...

я имел ввиду саму операцию ввода/вывода, что задействуется внутри Read()

согласен - реализовали это метод крайне криво, посему лично я класс TWinSocketStream никогда не использую и другим категорически не рекомендую


Digitman   (2004-03-19 11:11:00) [42]


> Verg ©   (19.03.04 10:59) [13]


а waitfordata-то здесь причем ? он не имеет отношения ни к overlapped-операции ввода ни к ивенту ..

ну да, ну вернул он True, что-то там в приехало ..

теперь мы стартуем/рестартуем собственно overlapped-операцию (неблокирующую по определению), после чего тут же анализируем сигнал ивента .. предположим, из запрошенных 18 байт на момент анализа ивента в файловом потоке ввода доступно всего 9 байт ... разумеется, ивент не просигналил еще ! ... а раз не просигналил, то и Result = 0...

ну и иная ситуация (та на которую ты намекаешь) - ивент просигналил, но в файловом потоке есть EOF ... тогда Read() вернет из overlapped-структуры то число байт, что находится в файловом потоке ДО Eof ... и вполне возможно, что до EOF ничего и не приходило ... тогда ситуация с Result = 0 так же объяснима


Verg   (2004-03-19 10:59:00) [43]


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


Нет, ты забыл что ли, что waitfordata уже сработал, т.е. в приемном буфере сокета уже что-то должно быть - хоть данные, хоть EOF


Verg   (2004-03-19 10:55:00) [44]

2 Digitman


>    if FEvent.WaitFor(FTimeOut) <> wrSignaled then //нет
> данных в буфере приема
>     Result := 0


Вот это есть некая "кривость". Потому как в результате невозможно отличить ситуацию таймаута от ситуации EOF (разрыв соединения собеседником).
Хоть бы -1 присвоили что-ли...

Сокет тем временем именно в блокирующем режиме. А для того, чтобы обеспечить возможность таймаута при чтении там воспользовались Overlapped IO с блокировкаой WaitForSingleObject (хотя можно было бы и select+recv-ом также все сделать).

Т.о. метод Read этого TWinSocketStream блокирующий по сути своей. Т.е. он не вернет управление потоку до тех пор, пока операция не закончится хоть с каким-то результатом.


Digitman   (2004-03-19 10:52:00) [45]


> Verg ©   (19.03.04 10:25) [5]


да, я здесь был неточен

гнездо-то само по себе иниц-но для работы в блок.режиме, но работа с ним идет с использованием файлового overlapped-ввода/вывода, что само по себе подразумевает неблок.режим ввода/вывода


> slgeo


вот цитата :

The event specified in the OVERLAPPED structure is set to the signaled state upon completion of the read operation.

это означает, что сигнал ивента следует ожидать только ПОСЛЕ приема и доступности в файловом буфере тех самых запрошенных тобой 18-ти байт

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


slgeo   (2004-03-19 10:44:00) [46]

и дальше естесвенно
     ms.Position := 0;
     ms.SaveToFile(ExtractFilePath(Application.ExeName)'+'update.txt');
     ms.Free;


slgeo   (2004-03-19 10:43:00) [47]

вот так точнее
var
ms : TMemoryStream;

    if Stream.WaitForData(60000) then
     begin
       Buf := '';
       SetLength(Buf, 256);
       FMaxProgress := fsize;
       Synchronize(DoMaxProgress);
       while True do
       begin
         nRead := Stream.Read(Buf[1],256);
         if Pos('000000!',Buf)>0 then
         begin
           StrIn := Copy(Buf,1,Pos('000000!',Buf)-1);
           ms.Write (strIn[1], Length(strIn));
           FMaxProgress := 0;
           Synchronize(DoMaxProgress);
           Break;
         end
         else
           ms.Write(Buf[1], nRead);
       end;
     end else
         begin
           FLogMsg := 'Не получен очередной пакет обновления!!!';
           Synchronize(DoLog);
           Exit;
         end;


Verg   (2004-03-19 10:37:00) [48]

Я там не вижу никакого "приема файла". Я там вижу ожидание появления данных в сокете и попытку проичтать из него не более 18-ти байтов в строку.
Какой файл? Где файл?


Digitman   (2004-03-19 10:36:00) [49]

при использовании TWinSocketStream.Read запускается асинхроннаяoverlapped-операция ввода

блокирование вызывающего код.потока происходит здесь
 if FEvent.WaitFor(FTimeOut) <> wrSignaled then

а здесь - неблокирующая операция ввода
   if not ReadFile(FSocket.SocketHandle, Buffer, Count, DWORD(Result),
      @Overlapped) and (GetLastError <> ERROR_IO_PENDING) then
   begin
     ErrorCode := GetLastError;
     raise ESocketError.CreateResFmt(@sSocketIOError, [sSocketRead, ErrorCode,
       SysErrorMessage(ErrorCode)]);
   end;


slgeo   (2004-03-19 10:32:00) [50]

>Verg

во-во это уже ближе, в Buf попадает что-то типа PK.... (если я не ошибаюсь это действительно признак конца файла). Но ведь с другой стороны был передан файл??? Куда он пропал?

Кстати выше по коду перед приемом файла у меня есть еще прием команды. Так вот в nRead снова 0, но в Buf данные попадают!!!


Verg   (2004-03-19 10:25:00) [51]

Если  это сработало (вернуло true)

>  if Stream.WaitForData(40000) then


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


> [2] Digitman ©   (19.03.04 10:12)


А с каким еще сокетом может работать TWinSocketStream, у которого есть метод WaitForData?


slgeo   (2004-03-19 10:19:00) [52]

to Digitman
с чего вдруг???
 OptClientThread = class(TThread)
 private
   ClientSocket: TClientSocket;
 ...
 end;

procedure OptClientThread.Execute;
var
 nRead: Integer;
 Stream: TWinSocketStream;  
 try
   ClientSocket := TClientSocket.Create (nil);
   Stream := nil;
   try
     ClientSocket.Address := ServerAddress;
     ClientSocket.ClientType := ctBlocking;
     ClientSocket.Port := RemotePort;
     ClientSocket.Active := True;
     Stream := TWinSocketStream.Create(ClientSocket.Socket, 30000);
 ...
 except
 ....
 end;


Digitman   (2004-03-19 10:15:00) [53]


> Verg ©   (19.03.04 10:10) [1]


уверен ?


   if FEvent.WaitFor(FTimeOut) <> wrSignaled then //нет данных в буфере приема
      Result := 0
   else
   begin
     GetOverlappedResult(FSocket.SocketHandle, Overlapped, DWORD(Result), False);
     FEvent.ResetEvent;
   end;


Digitman   (2004-03-19 10:12:00) [54]


> У меня идет обмен по блокирующим сокетам


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


Verg   (2004-03-19 10:10:00) [55]

nRead =0 в данном случае означает, что соединение было закрыто.


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

Наверх

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