![]() |
| ||
|
|
Новости |
Поиск |
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.
А то файл бьется.
Dmitriy Polskoy (2002-11-14 14:29:00) [21]Вот глянь, что я написал.
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:18:00) [22]
> а то хочу ... и не могу
Эт, сударь, уже на импотенцию смахивает ))))))))
Ну скажи на милость - ну что тут непонятного-то ? Я какие-то буквы/слова нерусские произношу или где ?
Dmitriy Polskoy (2002-11-14 14:07:00) [23]Я совсем запутался. Приведи пример, а то хочу разобраться и не могу.
Digitman (2002-11-14 13:52:00) [24]
> В OnRead возникает чтение
Ничего там не возникает. Компонент просто извещает тебя о том, что в буфере приема гнезда возможно не пуст. Можешь читать из буфера (сколько тебе угодно данных), а можешь вообще ничего не делать - твоя воля. Но при попытке чтения тебе будет передано ровно столько данных, сколько доступно в дан.момент в буфере приема. Но - не более чем показывает св-во ReceiveLength.
А речь-то идет не об OnRead, а об OnWrite.
> при помощи SendBuf передаю ...В этот момент
> возникает OnClientWrite
Ничего подобного. OnWrite БЕЗУСЛОВНО возникает как минимум
однократно сразу же за OnConnect.
Последующие OnWrite могут (но необязательно) возникнуть ТОЛЬКО ПОСЛЕ того, как ты вызвал один из send-методов.
Если send-метод вернул отказ, нет смысла повторять его в цикле, пока не "сработает" - буфер передачи занят в этот момент. Когда буфер освободится, компонент ОБЯЗАТЕЛЬНО сообщит тебе событием OnWrite, в котором ты снова можешь попытаться однократно выполнить send-метод, который опять же может дать отказ и т.д.
Для минимизации кол-ва отказов передачи в неблок.режиме рекомендуется вызывать send-метод для передачи блоков данных размером не более 4К
Dmitriy Polskoy (2002-11-14 13:34:00) [25]Исходя из кода в Dmitriy Polskoy © (14.11.02 13:03) понимаю так:
В OnRead возникает чтение из сокета имени файла, затем я читаю блок из него и при помощи SendBuf передаю его клиенту. В этот момент возникает OnClientWrite, в котором я проверяю кол-во реально переданных байт.
Digitman (2002-11-14 13:19:00) [26]а On(Client)Write когда, по-твоему возникает ? Вот расскажи, как ты себе понимаешь на данный момент логику возбуждения компонентом этого события : сколько раз, в какой момент, при каких условиях и т.п.
Dmitriy Polskoy (2002-11-14 13:16:00) [27]Да я читал. Получается, что в OnClientRead можно не вызывать SendBuf, а вызвать его уже в OnClientWrite. Ой, че-то я уже запутался.
Digitman (2002-11-14 13:06:00) [28]Вот это - фрагмент хэлпа, который ты ОБЯЗАН БЫЛ прочитать и понять до последней буквы, прежде чем браться за сколь-либо серьезное сетевое программирование с использованием того же 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:03:00) [29]Т.е. так
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 12:59:00) [30]В событии OnWrite() необходимо повторять передачу еще не переданных фрагментов данных, отказ (полный или частичный) передачи которых был обнаружен при попытку вызова send-метода, изначально инициирующего передачу
Dmitriy Polskoy (2002-11-14 12:54:00) [31]Ну хоть намекни как это делается. Ну пожалуста.
Digitman (2002-11-14 12:47:00) [32]Выход один - почитать про асинхронный неблокирующий режим работы гнезда и - очень внимательно - про событие On(Client)Write
Dmitriy Polskoy (2002-11-14 12:45:00) [33]Мой сервер передает так
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:41:00) [34]А какая разница - елиент передает или сервер ?
Абсолютно никакой. После установления соединения каджая из сторон в каждый момент времени может являться как приемником, так и передатчиком. В случае использования единых базовых транспортных классов (в дан. случае - TCustomWinSocket) и единых их режимов (в дан.случае - non-blocking) алгоритмы приема и передачи неких абстрактных поточных данных на обеих сторонах абсолютно идентичны.
Dmitriy Polskoy (2002-11-14 12:29:00) [35]Тоже, что и с клиентом - передает неправильное кол-во байт
Digitman (2002-11-14 12:15:00) [36]
> не получается никак.
Что не получается ?
Dmitriy Polskoy (2002-11-14 11:39:00) [37]2 Digitman © (14.11.02 11:19)
Согласен
А помоги сервером, а то не получается никак. См. Dmitriy Polskoy © (14.11.02 10:38)
Digitman (2002-11-14 11:19:00) [38]
> Buffer := temp_bufprt
Зачем ?
temp_bufptr := Buffer; // получить указательна начало буфера
Inc(temp_bufptr, TotalBytesRead); // прибавить смещение
Dmitriy Polskoy (2002-11-14 11:10:00) [39]2 Digitman © (14.11.02 11:01)
В таком случае надо
Buffer := temp_bufprt, а у тебя наоборот, или я, что-то не так понимаю.
Digitman (2002-11-14 11:06:00) [40]>Dmitriy Polskoy
Обратись к нему в форуме. Вообще-то я просил его выложить основные элементы программного решения на сайт.