Форум: "Сети";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.14;
Скачать: [xml.tar.bz2];




Вниз

С мольбой о помощи взываю!!! 


Polevi   (2001-10-17 11:45) [0]

Файл пытаюсь переслать :-)))
Все статьи прочитал, в форумах смотрел - у людей все работает, у у меня нет :((

Отсылаю

procedure TForm1.csConnect(Sender: TObject; Socket: TCustomWinSocket);
var
FS:TFileStream;
begin
FS:=TFileStream.Create("sour.ext",fmOpenRead);
cs.Socket.SendStream(FS);
FS.Free;
end;

Принимаю

procedure TClientThread.ClientExecute;
var
FS:TFileStream;
WSS:TWinSocketStream;
RL:integer;
begin
FS:=TFileStream.Create("dest.ext",fmCreate or fmOpenWrite);
WSS:=TWinSocketStream.Create(ClientSocket,20000);

try
while (not Terminated) and ClientSocket.Connected do
if WSS.WaitForData(20000) then
begin
RL:=ClientSocket.ReceiveLength;
if FS.CopyFrom(WSS, RL)=0 then break;
end;
finally
begin
ClientSocket.Close;
WSS.Free;
FS.Free;
end;
end;
end;

На маленьких файлах все работает..
Но если размер больше 4096 -
На строке CopyFrom - Stream read error

Я понимаю что тема заезжена - но не вижу я ошибки в коде!!
Помогите, плиз..



Digitman   (2001-10-17 12:52) [1]

procedure TClientThread.ClientExecute;
var
FS:TFileStream;
RL:integer;
SocketEvent: THandle;
buf: Pointer;
Msg: TMsg;
begin
try
FS:=TFileStream.Create("dest.ext",fmCreate or fmOpenWrite);
SocketEvent := WSACreateEvent;
WSAEventSelect(ClientSocket.SocketHandle, SocketEvent, FD_READ or FD_CLOSE);
try
while (not Terminated) and ClientSocket.Connected do

case MsgWaitForMultipleObjects(1, SocketEvent, False, INFINITE, QS_POSTMESSAGE) of
WAIT_OBJECT_0:
begin
RL:=ClientSocket.ReceiveLength;
if RL > 0 then begin
GetMem(buf, RL);
try
RL := ClientSocket.ReceiveBuf(buf^, RL);
FS.Write(buf^, RL)
finally
FreeMem(buf);
end;
end
end;
WAIT_OBJECT_0 + 1:
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
DispatchMessage(Msg);
end;
WAIT_ABANDONED: break;
end;
finally
CloseHandle(SocketEvent);
ClientSocket.Close;
FS.Free;
end;
except
// обработка ошибок
end;
end;



Evegeniy_S   (2001-10-17 12:53) [2]

а clienttype у тебя на сокете blocking?



Polevi   (2001-10-17 13:16) [3]

2Evegeniy_S
blocking

2Digitman
SocketEvent := WSACreateEvent; - здесь AV выскакивает :(
И если не трудно - можно небольшие комментарии?
Я не вижу здесь тайм-аута, например..



Digitman   (2001-10-17 13:51) [4]

что-то я глубоко сомневаюсь, что именно на SocketEvent := WSACreateEvent AV возбудится ...

Да, вот еще, в конце - не CloseHandle(SocketEvent), а WSACloseEvent(SocketEvent)

насчет тайм-аута - вместо INFINITE поставь время в мс и добавь в блок case..of вариант WAIT_TAIMAUT, в котором принимай решение, ждать дальше или закругляться



Polevi   (2001-10-17 14:25) [5]

Хм..
WSACreateEvent лежит в sconnect..

Вот эту ф-ию надо вызвать видимо???

function LoadWinSock2: Boolean;
const
DLLName = "ws2_32.dll";
begin
Result := hWinSock2 > HINSTANCE_ERROR;
if Result then Exit;
hWinSock2 := LoadLibrary(PChar(DLLName));
Result := hWinSock2 > HINSTANCE_ERROR;
if Result then
begin
WSACreateEvent := GetProcAddress(hWinSock2, "WSACreateEvent");
WSAResetEvent := GetProcAddress(hWinSock2, "WSAResetEvent");
WSACloseEvent := GetProcAddress(hWinSock2, "WSACloseEvent");
WSAEventSelect := GetProcAddress(hWinSock2, "WSAEventSelect");
end;
end;

Вызываю - AV пропадает, ессно..
Но возникает какаято жуткая тормозня и в итоге неичего не копируется..

?



Digitman   (2001-10-17 14:40) [6]

какая еще тормозня ? ты код трассировать умеешь ? оттассируй пошагово ClientExecute() - только тогда будешь иметь представление, что делается в каждой строчке. И вопрос сам по себе отпадет.



Polevi   (2001-10-17 15:23) [7]

Оттрассировал..
Почему "тормозит" понял

if RL > 0 then begin
GetMem(buf, RL);
try
RL := ClientSocket.ReceiveBuf(buf^, RL);
FS.Write(buf^, RL)
finally
FreeMem(buf);
end;

Так вот если RL<=0 то цикл зависает, и ни по какому тайм-ауту не выходит..
Если поставить else break; - то первые 4k копируются и все... (else break срабатывает, видимо)
"Видимо" потому что в пошаговом режиме все вроде копируется, а если точки останова убрать - начинается см. выще.

Щас полезу в исходники разбираться..
Халява не прошла :-)))




Polevi   (2001-10-17 16:13) [8]

Мдаа..
Переделал первоначальный вариант - отказался от CopyFrom, сделал все ручками - и все заработало на славу :-))
Вот ведь как бывает..



Digitman   (2001-10-17 16:37) [9]

Ты пойми, что сервер ничего не знает о полном размере данных, который клиент хочет передать. Для этого клиент перед посылкой собственно данных должен послать некий префикс, значение которого позволит серверу определиться, какой длины данные суммарно будут переданы. И в цикл нужно добавить условие (переменная-счетчик, работающий на вычитание размера очер.порции принятых данных, начальное значение которой формируется из считанного префикса), проверяющее, все ли данные считаны. Протокол-то - поточный ! Цикл надо прервать, когда Счетчик = 0, тогда и файл закроется и обработка завершится.
Приведенный код - лишь скелет, показывающий, как работать с поточным гнездом. Доработай его сам (и - осознанно, а не методом тыка !) с учетом этих замечаний - и убедишься в преимуществе над использованием TWinSocketStream



Polevi   (2001-10-17 18:39) [10]

Да, я все осознал, спасибо :-)
Я просто почемуто думал, что если ReceiveLength=0 то значит все уже скопировано..
Но все равно непонятно, почему по таймауту не выходил я из цикла..
Вместо INFINITE ставил занчение в милисек и на TIMEOUT не выходил..
Ну впрочем это видимо руки у меня кривые :-)



Digitman   (2001-10-18 08:52) [11]

>Polevi
Я еще вот чего важное забыл (спешил, извини уж, но - мог бы и сам догадаться, почитав хэлп на сабж)

Всякий раз в блоке WAIT_OBJECT_0 перевым делом нужно сбросить сигнал объекта синхронизации SocketEvent в нач.сотояние вызовом WSAResetEvent(SocketEvent), иначе он останется в сигналящем состоянии и ты больше не дождешься его срабатывания по событиям в гнезде.

Можно обойтись и без WSAResetEvent(), но тогда нужно использовать вызов WSAEnumNetworkEvents(), автоматически сбрасывающий сигн.объект. Это чуть сложнее, но зато дает большую гибкость в обработке гнездовых событий (в т.ч. немедленное получение инфы об ошибках, связанных с тем или иным событием без необходимости их обнаружения иными методами/вызовами)



Polevi   (2001-10-18 10:07) [12]

Спасибо, буду разбираться.




Форум: "Сети";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.14;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.75 MB
Время: 0.019 c
1-42422           dimonf                2001-12-25 19:37  2002.01.14  
Как работать с Canvas в StringGrid?


1-42498           Alan                  2001-12-25 19:16  2002.01.14  
Проблемка с постоянным отображением подсказки


1-42456           777                   2001-12-25 04:10  2002.01.14  
Ширина колонок TDBGrid


1-42480           Ser_Kham1             2001-12-25 12:08  2002.01.14  
ListBox


4-42596           eSc!                  2001-10-29 23:19  2002.01.14  
LockWorkstation();