![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Не возвращается количество полученных байт в блокирующисокетах??? [D6, Win2k]
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 в данном случае означает, что соединение было закрыто.