Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2003.01.16;
Скачать: [xml.tar.bz2];

Вниз

ClientSocket   Найти похожие ветки 

 
Dmitriy Polskoy   (2002-11-14 12:29) [40]

Тоже, что и с клиентом - передает неправильное кол-во байт


 
Digitman   (2002-11-14 12:41) [41]

А какая разница - елиент передает или сервер ?
Абсолютно никакой. После установления соединения каджая из сторон в каждый момент времени может являться как приемником, так и передатчиком. В случае использования единых базовых транспортных классов (в дан. случае - TCustomWinSocket) и единых их режимов (в дан.случае - non-blocking) алгоритмы приема и передачи неких абстрактных поточных данных на обеих сторонах абсолютно идентичны.


 
Dmitriy Polskoy   (2002-11-14 12:45) [42]

Мой сервер передает так
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
LasrPos, temp: Integer;
bufprt: PChar;
begin
FileName := Socket.ReceiveText;

AssignFile(SrcFile, FileName);
Reset(SrcFile,1);
try
repeat
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
bufprt := @Buffer[1];
Res := ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
if Res = -1 then Inc(TotalBytesRead, 0)
else
Inc(TotalBytesRead, Res);
while (TotalBytesRead <> BytesRead) and ((Res >= 0) or (Res = -1)) do
begin
while Res = -1 do
begin
Sleep(3);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufprt^, BytesRead);
if Res <> -1 then Inc(TotalBytesRead, Res);
end;

Inc(bufprt, TotalBytesRead);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufprt^, BytesRead);
if Res <> -1 then Inc(TotalBytesRead, Res);
end;

sum := sum + TotalBytesRead;
TotalBytesRead := 0;
label1.Caption := inttostr(sum);
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;

На выделенном участке уходит в долгий-долгий цикл, т.е. получается, что никак не может передать данные. Какой выход?


 
Digitman   (2002-11-14 12:47) [43]

Выход один - почитать про асинхронный неблокирующий режим работы гнезда и - очень внимательно - про событие On(Client)Write


 
Dmitriy Polskoy   (2002-11-14 12:54) [44]

Ну хоть намекни как это делается. Ну пожалуста.


 
Digitman   (2002-11-14 12:59) [45]

В событии OnWrite() необходимо повторять передачу еще не переданных фрагментов данных, отказ (полный или частичный) передачи которых был обнаружен при попытку вызова send-метода, изначально инициирующего передачу


 
Dmitriy Polskoy   (2002-11-14 13:03) [46]

Т.е. так
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
LasrPos, temp: Integer;

begin
FileName := Socket.ReceiveText;

AssignFile(SrcFile, FileName);
Reset(SrcFile,1);
try
repeat
bufprt := @Buffer[1];
BlockRead(SrcFile, Buffer, SizeOf(Buffer), BytesRead);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufprt^, BytesRead);

until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;

procedure TForm1.ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Res = -1 then Inc(TotalBytesRead, 0)
else
Inc(TotalBytesRead, Res);
while (TotalBytesRead <> BytesRead) and ((Res >= 0) or (Res = -1)) do
begin
while Res = -1 do
begin
Sleep(3);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufprt^, BytesRead);
if Res <> -1 then Inc(TotalBytesRead, Res);
end;
Inc(bufprt, TotalBytesRead);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufprt^, BytesRead);
if Res <> -1 then Inc(TotalBytesRead, Res);
end;
sum := sum + TotalBytesRead;
TotalBytesRead := 0;
label1.Caption := inttostr(sum);
end;


 
Digitman   (2002-11-14 13:06) [47]

Вот это - фрагмент хэлпа, который ты ОБЯЗАН БЫЛ прочитать и понять до последней буквы, прежде чем браться за сколь-либо серьезное сетевое программирование с использованием того же TCustomWinSocket :

Writes Count bytes to the socket connection from the Buf parameter.

function SendBuf(var Buf; Count: Integer): Integer;

Description

Use SendBuf to write to the socket connection. Call this method from the OnSocketEvent event handler of a Windows socket object or in the OnWrite or OnClientWrite event handler of a socket component. Alternately, Use SendBuf to write when a connection is first formed when the socket does not expect notification that the socket on the other end of the connection is expecting to read.

For non-blocking sockets, the data is sent to the WinSock DLL which has it"s own internal buffers. If the WinSock can accept additional data, SendBuf returns immediately with the number of bytes queued. If the WinSock internal buffer space is not able to accept the buffer being sent, SendBuf returns -1 and no data is queued at all. In this case, wait a bit for the WinSock to have a chance to send out already-queued data; then try again.

For blocking sockets, SendBuf returns the number of bytes actually written.

If an error occurs while writing to the connection, SendBuf terminates the connection and raises an ESocketError exception.

Тебе перевести и разжевать ? Или таки сам удосужишься ?


 
Dmitriy Polskoy   (2002-11-14 13:16) [48]

Да я читал. Получается, что в OnClientRead можно не вызывать SendBuf, а вызвать его уже в OnClientWrite. Ой, че-то я уже запутался.


 
Digitman   (2002-11-14 13:19) [49]

а On(Client)Write когда, по-твоему возникает ? Вот расскажи, как ты себе понимаешь на данный момент логику возбуждения компонентом этого события : сколько раз, в какой момент, при каких условиях и т.п.


 
Dmitriy Polskoy   (2002-11-14 13:34) [50]

Исходя из кода в Dmitriy Polskoy © (14.11.02 13:03) понимаю так:
В OnRead возникает чтение из сокета имени файла, затем я читаю блок из него и при помощи SendBuf передаю его клиенту. В этот момент возникает OnClientWrite, в котором я проверяю кол-во реально переданных байт.


 
Digitman   (2002-11-14 13:52) [51]


> В OnRead возникает чтение


Ничего там не возникает. Компонент просто извещает тебя о том, что в буфере приема гнезда возможно не пуст. Можешь читать из буфера (сколько тебе угодно данных), а можешь вообще ничего не делать - твоя воля. Но при попытке чтения тебе будет передано ровно столько данных, сколько доступно в дан.момент в буфере приема. Но - не более чем показывает св-во ReceiveLength.

А речь-то идет не об OnRead, а об OnWrite.


> при помощи SendBuf передаю ...В этот момент
> возникает OnClientWrite


Ничего подобного. OnWrite БЕЗУСЛОВНО возникает как минимум
однократно сразу же за OnConnect.

Последующие OnWrite могут (но необязательно) возникнуть ТОЛЬКО ПОСЛЕ того, как ты вызвал один из send-методов.

Если send-метод вернул отказ, нет смысла повторять его в цикле, пока не "сработает" - буфер передачи занят в этот момент. Когда буфер освободится, компонент ОБЯЗАТЕЛЬНО сообщит тебе событием OnWrite, в котором ты снова можешь попытаться однократно выполнить send-метод, который опять же может дать отказ и т.д.

Для минимизации кол-ва отказов передачи в неблок.режиме рекомендуется вызывать send-метод для передачи блоков данных размером не более 4К


 
Dmitriy Polskoy   (2002-11-14 14:07) [52]

Я совсем запутался. Приведи пример, а то хочу разобраться и не могу.


 
Digitman   (2002-11-14 14:18) [53]


> а то хочу ... и не могу


Эт, сударь, уже на импотенцию смахивает ))))))))

Ну скажи на милость - ну что тут непонятного-то ? Я какие-то буквы/слова нерусские произношу или где ?


 
Dmitriy Polskoy   (2002-11-14 14:29) [54]

Вот глянь, что я написал.

procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
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);
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;

procedure TForm1.ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Res = -1 then Exit;
BytesRemainsToSend := BytesRead - TotalBytesSend;
bufptr := @Buffer[1];
Inc(bufptr, TotalBytesSend);
Res := ServerSocket.Socket.Connections[0].SendBuf(bufptr^, BytesRemainsToSend);
if Res >= 0 then
begin
Inc(TotalBytesSend, Res);
if TotalBytesSend = BytesRead then
TotalBytesSend := 0;
end;
sum := sum + TotalBytesSend;
label1.Caption := inttostr(sum);
end;


Кстати у меня вопос - как в OnClientRead в блоке repeat/until добиться задержки следующей итерации в случае -1. Не потеряются ли данные, посланные на предыдущей итерации (с результатом -1) при переходе к следующей.


 
Digitman   (2002-11-14 14:47) [55]

Да нежелательно вообще цикл в событии делать !!
Упомянутый мной цикл приемлем будет лишь для блок.режима, но у тебя-то - неблокирующий !

Пока ты циклишь передачу, ни одно событие не будет вызвано. Тем более, что после нескольких итераций ты будешь раз за разом получать отказ передачи блока - буфер передачи будет наполнен, и пока данные из него не будут физически отправлены, буфер не освободится. Что толку продолжать пытаться "толкать" в него очер.блок данных в итерации ?

Вызвал в какой-то итерации send-метод , получил отказ - зафиксируй где-либо вне обработчика события параметры отказавшей итерации и успокойся на этом, завершив обработку события.
Возникнет OnWrite - возобнови в его обработчике цикл с той итерации, на которой остановился и параметры которой запомнил.
Если же и в OnWrite после какой-то очередной send-итерации возник отказ - то же самое : запоминай параметры итерации и "успокойся", завершив обработку OnWrite, ибо оно возникнет снова и продолжишь в нем цикл с запомненной итерации. И так до тех пор , пока не будет достигнут последний шаг итерации


 
Dmitriy Polskoy   (2002-11-14 14:56) [56]

Ну приведи пример пожалуста-а-а. Не пойму как кОдить и все.


 
Digitman   (2002-11-14 14:59) [57]


> Dmitriy Polskoy


И не подумаю. Шевели мозгами, если ты программер, а не кодер.


 
Dmitriy Polskoy   (2002-11-14 15:01) [58]

Злой ты :-))


 
Dmitriy Polskoy   (2002-11-14 15:06) [59]

А что если во время итерации предастся меньшее кол-во байт, чем в буфере?


 
Dmitriy Polskoy   (2002-11-14 15:16) [60]

Я как в стену уперся - не могу понять и все. Покажи как это сделать - я увижу и запомню раз и навсегда.


 
Digitman   (2002-11-14 15:41) [61]

в буфере чего ?


 
Dmitriy Polskoy   (2002-11-14 15:47) [62]

В буфере, который передается.


 
Digitman   (2002-11-14 16:09) [63]

каждая итерация будет требовать некий нач.адрес данных и их размер

если содержимое буфера передано не полностью, ReceiveBuf(addr = buffer, count = bufsize) вернет некое число Res >= 0.

это значит, что , раз буфер передан не полностью, очередной вызов ReceiveBuf() д.б. выполнен с параметрами

addr = buffer + Res
и
count = bufsize - Res

Это тоже непонятно ?


 
Dmitriy Polskoy   (2002-11-14 16:59) [64]

Вот на что спромогся. Поправь если что.

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


 
Dmitriy Polskoy   (2002-11-14 17:10) [65]

Мне еще не понятно (опираюсь на последний мой код)где нужно вызывать BlockRead, после того, как я вышел из цикла в OnClientRead.


 
Digitman   (2002-11-14 17:17) [66]

ладно, бросай на время рассуждения о "высоких материях"
у тебя даже приемник как положено рпботать не будет, а ты передачей озабочен

смотри сюда :


procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
FileName: string;
begin
FileName := Socket.ReceiveText; // (*)
... и т.д.


НА ОСНОВАНИИ ЧЕГО ты уверен, что после выполнения строчки (*) переменная FileName будет В ТОЧНОСТИ соответствовать тому, что послал передатчик ?


> И мне кажеться, что вызывая Send-метот внутри OnClientWrite,
> я рекурсивно вызываю этот самый OnClientWrite


НА ОСНОВАНИИ ЧЕГО тебе это кажется ?


 
Dmitriy Polskoy   (2002-11-14 17:36) [67]

Да потому, что не работал я с этим никогда. Пршу ведь тебя помоги написать, я когда увижу как это правильно делается хоть знать буду да рассуждать смогу.


 
Digitman   (2002-11-14 17:42) [68]


> Да потому, что не работал я с этим никогда.


Не работал ? Не берись за работу !
А если взялся - изучи прежде внимательнейшим образом всю документацию, относящуюся к теме.
И ведь исх.тексты от Борланда - всегда под рукой ! Ну неужели так трудно заглянуть в них и проанализировать, что делает в том или ином случае сам Борланд ? Чем? собственно, будет отличаться тот код, что ты от меня требуешь, от того что у тебя перед носом, в файле scktcomp.pas. Ничем абсолютно ! Я просто продублирую тебе его...

Начни с http://books.itep.ru

Там есть, imho, достаточно неплохие статьи по основам построения сетей и вполне сносное описание большей части спецификации Winsock - что, зачем, как работает и как следует применять.


 
savva   (2002-11-15 09:19) [69]

> Digitman © (14.11.02 17:42)
> Начни с http://books.itep.ru
точнее http://book.itep.ru/


 
Dmitiy Polskoy   (2002-11-15 19:07) [70]

Ладно, сдаюсь. Кто-нибудь может мне ответить на один вопрос.
Когда именно возникает 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;


 
Dmitiy Polskoy   (2002-11-15 19:12) [71]

По поводу http://book.itep.ru/. Я это читал и даже книга у меня есть на эту тему. Вот сижу разбираюсь. Проблема в другом - программу мне здать надо скоро вот поэтому и прошу о помощи.


 
Maksss   (2002-11-15 19:23) [72]

помоему глупо упиратся в размер ресива
не проще сначала передать размер файла а потом собирать весь ресив например в мемористреам


 
Maksss   (2002-11-15 19:30) [73]

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);


 
stikriz   (2002-11-17 16:00) [74]

Дмитрий.
Вот тут недалеко есть такая ветка
http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1035121869&n=4
А Ваша ошибка состоит в том, что Вы не знаете на самом деле сколько передано данных. Можно почитать ветку, которую я указал, но там есть тоже ошибка - помечать пакеты, а можно просто понять, что:
1) Это достаточно низкоуровневый механизм, поэтому что-то придется дополнительно предпринимать, чтобы все работало.
2) Эти компоненты просто посылают байтики и все. Остальное - Ваши проблеммы.
3) Надо как-то передавать клиенту к-во байтов, которые он должен принять.
4) Стараться не путать пакеты, т.е. пока передается файл, например, не передавать другие данные, а то все спутается.
5) Сколько возвращает ф-ция Receive... Столько и пришло, а остальное не потерялось - оно просто идет :-)

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

Успехов, Николай.



Страницы: 1 2 вся ветка

Форум: "Сети";
Текущий архив: 2003.01.16;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.61 MB
Время: 0.011 c
14-49310
Странник
2002-12-28 13:47
2003.01.16
И опять о лицензионности софта.


3-48910
gunner
2002-12-20 16:04
2003.01.16
Утечка памяти в ADOStoredProc


1-48983
Kromag
2003-01-06 18:56
2003.01.16
Генерация


1-49073
Оля
2003-01-08 12:00
2003.01.16
MDIForm 8...(


3-48881
Sword-Fish
2002-12-20 00:32
2003.01.16
SQL-запросы





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский