![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
ClientSocket [D6, Win2k]
Dmitriy Polskoy © (2002-11-13 14:43:00)Подскажите, как сделать так, чтобы ClientSocket принимал ровно столько сколько передает ServerSocket. Объясняю - ServerSocket в
OnClientRead получает имя файла и затем передает его клиенту по 500 байт
AssignFile(SrcFile, FileName);
Reset(SrcFile,1);
try
repeat
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
А клиент принимет, но не 500 байт за раз, а другое число байт.
Я знаю, что это нормально, но как сделать, чтобы и принимал 500.
А то файл бьется.
stikriz (2002-11-17 16:00:00) [1]Дмитрий.
Вот тут недалеко есть такая ветка
http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1035121869&n=4
А Ваша ошибка состоит в том, что Вы не знаете на самом деле сколько передано данных. Можно почитать ветку, которую я указал, но там есть тоже ошибка - помечать пакеты, а можно просто понять, что:
1) Это достаточно низкоуровневый механизм, поэтому что-то придется дополнительно предпринимать, чтобы все работало.
2) Эти компоненты просто посылают байтики и все. Остальное - Ваши проблеммы.
3) Надо как-то передавать клиенту к-во байтов, которые он должен принять.
4) Стараться не путать пакеты, т.е. пока передается файл, например, не передавать другие данные, а то все спутается.
5) Сколько возвращает ф-ция Receive... Столько и пришло, а остальное не потерялось - оно просто идет :-)
Итак, передали размер, и читайте, пока ве данные не выгребете и все... Нет никаких сложностей - только легкие неудобства.
Успехов, Николай.
Maksss (2002-11-15 19:30:00) [2]var Receiving : boolean;
DataSize :int64;
Data : TMemoryStream;
это приём:
procedure TClient1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var s: string;
begin
s:= Socket.ReceiveText;
if not Reciving then begin
SetLength(sl, StrLen(PChar(s))+1);
StrLCopy(@sl[1], PChar(s), Length(sl)-1);
DataSize:= StrToInt(sl);
Data:= TMemoryStream.Create;
Delete(s, 1, Length(sl));
Reciving:= true;
end;
try
Data.Write(s[1], length(s));
if Data.Size = DataSize then begin
Data.Position:= 0;
Data.SaveToFile(file....
"это передача:
Data.LoadFromFile(OpenDialog1.FileName);
Data.Position:= 0;
ClientSocket1.Socket.SendText(IntToStr(Data.Size) + #0);
ClientSocket1.Socket.SendStream(Data);
Maksss (2002-11-15 19:23:00) [3]помоему глупо упиратся в размер ресива
не проще сначала передать размер файла а потом собирать весь ресив например в мемористреам
Dmitiy Polskoy (2002-11-15 19:12:00) [4]По поводу http://book.itep.ru/.Я это читал и даже книга у меня есть на эту тему. Вот сижу разбираюсь. Проблема в другом - программу мне здать надо скоро вот поэтому и прошу о помощи.
Dmitiy Polskoy (2002-11-15 19:07:00) [5]Ладно, сдаюсь. Кто-нибудь может мне ответить на один вопрос.
Когда именно возникает OnClientWrite. В следующем коде я пытаюсь
в этом обработчике сбрасывать значеник переменной в True. Но она так никогда и не збрасывается.
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
FileName := Socket.ReceiveText;
AssignFile(SrcFile, FileName);
Reset(SrcFile, 1);
try
repeat
if ok then
begin
if Res < BytesRead then
begin
Inc(Bufptr, Res);
BytesRead := BytesRead - Res;
Res := ServerSocket.Socket.Connections[0].SendBuf(Bufptr^, BytesRead);
if Res = -1 then
begin
Res := 0;
ok := false;
end;
Inc(SendSize, Res);
Label1.Caption := IntToStr(SendSize);
end;
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
Bufptr := @Buffer[1];
Res := ServerSocket.Socket.Connections[0].SendBuf(Bufptr^, BytesRead);
if Res = -1 then
begin
Res := 0;
ok := false;
end;
Inc(SendSize, Res);
Label1.Caption := IntToStr(SendSize);
end
else if not ok then
begin
Exit;
Application.ProcessMessages;
Continue;
end;
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;
procedure TForm1.ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
ok:=true;
end;
savva (2002-11-15 09:19:00) [6]> Digitman © (14.11.02 17:42)
> Начни с http://books.itep.ru
точнее http://book.itep.ru/
Digitman (2002-11-14 17:42:00) [7]
> Да потому, что не работал я с этим никогда.
Не работал ? Не берись за работу !
А если взялся - изучи прежде внимательнейшим образом всю документацию, относящуюся к теме.
И ведь исх.тексты от Борланда - всегда под рукой ! Ну неужели так трудно заглянуть в них и проанализировать, что делает в том или ином случае сам Борланд ? Чем? собственно, будет отличаться тот код, что ты от меня требуешь, от того что у тебя перед носом, в файле scktcomp.pas. Ничем абсолютно ! Я просто продублирую тебе его...
Начни с http://books.itep.ru
Там есть, imho, достаточно неплохие статьи по основам построения сетей и вполне сносное описание большей части спецификации Winsock - что, зачем, как работает и как следует применять.
Dmitriy Polskoy (2002-11-14 17:36:00) [8]Да потому, что не работал я с этим никогда. Пршу ведь тебя помоги написать, я когда увижу как это правильно делается хоть знать буду да рассуждать смогу.
Digitman (2002-11-14 17:17:00) [9]ладно, бросай на время рассуждения о "высоких материях"
у тебя даже приемник как положено рпботать не будет, а ты передачей озабочен
смотри сюда :
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
FileName: string;
begin
FileName := Socket.ReceiveText; // (*)
... и т.д.
НА ОСНОВАНИИ ЧЕГО ты уверен, что после выполнения строчки (*) переменная FileName будет В ТОЧНОСТИ соответствовать тому, что послал передатчик ?
> И мне кажеться, что вызывая Send-метот внутри OnClientWrite,
> я рекурсивно вызываю этот самый OnClientWrite
НА ОСНОВАНИИ ЧЕГО тебе это кажется ?
Dmitriy Polskoy (2002-11-14 17:10:00) [10]Мне еще не понятно (опираюсь на последний мой код)где нужно вызывать BlockRead, после того, как я вышел из цикла в OnClientRead.
Dmitriy Polskoy (2002-11-14 16:59:00) [11]Вот на что спромогся. Поправь если что.
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
FileName: string;
begin
FileName := Socket.ReceiveText;
AssignFile(SrcFile, FileName);
Reset(SrcFile,1);
try
repeat
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
Res := ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
if (Res < BytesRead) or(Res = -1) then Exit;
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;
procedure TForm1.ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Res = BytesRead then Exit;
if Res = -1 then Res := 0;
bufptr := @Buffer[1];
Inc(bufptr, Res);
BytesRead := BytesRead - Res;
Res := ServerSocket.Socket.Connections[0].SendBuf(bufptr^, BytesRead);
if (Res < BytesRead) or (Res = -1) then Exit;
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
Res := 0;
label1.Caption := inttostr(TotalSize);
end;
И мне кажеться, что вызывая Send-метот внутри OnClientWrite, я рекурсивно вызываю этот самый OnClientWrite
Digitman (2002-11-14 16:09:00) [12]каждая итерация будет требовать некий нач.адрес данных и их размер
если содержимое буфера передано не полностью, ReceiveBuf(addr = buffer, count = bufsize) вернет некое число Res >= 0.
это значит, что , раз буфер передан не полностью, очередной вызов ReceiveBuf() д.б. выполнен с параметрами
addr = buffer + Res
и
count = bufsize - Res
Это тоже непонятно ?
Dmitriy Polskoy (2002-11-14 15:47:00) [13]В буфере, который передается.
Digitman (2002-11-14 15:41:00) [14]в буфере чего ?
Dmitriy Polskoy (2002-11-14 15:16:00) [15]Я как в стену уперся - не могу понять и все. Покажи как это сделать - я увижу и запомню раз и навсегда.
Dmitriy Polskoy (2002-11-14 15:06:00) [16]А что если во время итерации предастся меньшее кол-во байт, чем в буфере?
Dmitriy Polskoy (2002-11-14 15:01:00) [17]Злой ты :-))
Digitman (2002-11-14 14:59:00) [18]
> Dmitriy Polskoy
И не подумаю. Шевели мозгами, если ты программер, а не кодер.
Dmitriy Polskoy (2002-11-14 14:56:00) [19]Ну приведи пример пожалуста-а-а. Не пойму как кОдить и все.
Digitman (2002-11-14 14:47:00) [20]Да нежелательно вообще цикл в событии делать !!
Упомянутый мной цикл приемлем будет лишь для блок.режима, но у тебя-то - неблокирующий !
Пока ты циклишь передачу, ни одно событие не будет вызвано. Тем более, что после нескольких итераций ты будешь раз за разом получать отказ передачи блока - буфер передачи будет наполнен, и пока данные из него не будут физически отправлены, буфер не освободится. Что толку продолжать пытаться "толкать" в него очер.блок данных в итерации ?
Вызвал в какой-то итерации send-метод , получил отказ - зафиксируй где-либо вне обработчика события параметры отказавшей итерации и успокойся на этом, завершив обработку события.
Возникнет OnWrite - возобнови в его обработчике цикл с той итерации, на которой остановился и параметры которой запомнил.
Если же и в OnWrite после какой-то очередной send-итерации возник отказ - то же самое : запоминай параметры итерации и "успокойся", завершив обработку OnWrite, ибо оно возникнет снова и продолжишь в нем цикл с запомненной итерации. И так до тех пор , пока не будет достигнут последний шаг итерации