Форум: "Сети";
Текущий архив: 2003.01.16;
Скачать: [xml.tar.bz2];
ВнизClientSocket Найти похожие ветки
← →
Dmitriy Polskoy (2002-11-13 14:43) [0]Подскажите, как сделать так, чтобы 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.
А то файл бьется.
← →
Song (2002-11-13 14:47) [1]В приведённом примере не видно когда Вы делаете закрытие сокета.
← →
F1 (2002-11-13 14:50) [2]ClientSocket1.Socket.ReceiveBuf(buf,500); ???
← →
Dmitriy Polskoy (2002-11-13 14:56) [3]Сокет я закрываю при закрытии клиента.
Кстати на небольших объемах (до 1 Мб) файл передается нормально,
а например, при файл в 170 Мб отправляется весь объем, а принимается меньше. Где он теряется?
← →
Dmitriy Polskoy (2002-11-13 15:01) [4]2 F1 © (13.11.02 14:50)
Не получится, т.к в OnRead надо получить кол-во байт, которое пришло. Иначе опять будет сбой - файл оказывается в ~4 раза больше
← →
Digitman (2002-11-13 15:01) [5]
> как сделать, чтобы и принимал 500.
Принимай не более 500 байт за один раз. И всех делов.
см. function ReceiveBuf(var Buf; Count: Integer): Integer;
Count - сколько запросил для приема
Result - сколько реально принято
Result >= 0 , но Result < Count ?
Не проблема. Уменьшай Count на значение Result, смещай позицию в буфере на значение Result и повторяй в цикле, пока Count > 0. После этого передавай адрес цельного принятого блока в 500 байт на обработку.
← →
F1 (2002-11-13 15:05) [6]>Dmitriy Polskoy © (13.11.02 15:01)
>Не получится, т.к в OnRead...
А циклы начто???
← →
Dmitriy Polskoy (2002-11-13 15:07) [7]2 Digitman © (13.11.02 15:01)
А как решить Dmitriy Polskoy © (13.11.02 15:01) и
если Result > Count?
← →
F1 (2002-11-13 15:08) [8]Result не может быть > Count!!!
← →
Dmitriy Polskoy (2002-11-13 15:10) [9]2 all
Делаю так, а как надо?
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
begin
BytesRead := Socket.ReceiveLength;
Socket.ReceiveBuf(Buffer, BytesRead);
BlockWrite(DestFile, Buffer, BytesRead, BytesWritten);
sum := sum + bytesread;
label1.Caption := inttostr(sum);
end;
← →
Dmitriy Polskoy (2002-11-13 15:13) [10]2 F1 © (13.11.02 15:08)
Да. Это я протупил.
← →
F1 (2002-11-13 15:14) [11]А тогда зачем тебе именно по 500 байт читать???
Или все-таки надо???
← →
F1 (2002-11-13 15:16) [12]Кстати Digitman уже много раз писал как ПРАВИЛЬНО передавать данные чере сокеты, поищи.
← →
Dmitriy Polskoy (2002-11-13 15:21) [13]Да читал я. И вроде все работает, но на определенных размерах, а потом байты теряются. По 500 это непринципиально. Это число мой сервер будет определять исходя из размера файла.
← →
F1 (2002-11-13 15:27) [14]Попробуй так:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
begin
BytesRead := Socket.ReceiveLength;
Res:=Socket.ReceiveBuf(Buffer, BytesRead);
BlockWrite(DestFile, Buffer, Res, BytesWritten);
sum := sum + Res;
label1.Caption := inttostr(sum);
end;
А то что Digitman раньше писал, точно работает!!!
Он по сетям хороший спец!!!
← →
Dmitriy Polskoy (2002-11-13 15:37) [15]Все равно принимаю меньше чем отправляю.
Кстати, помоги найти то, что писал Digitman. Может я что-то не то читал.
← →
F1 (2002-11-13 15:41) [16]А покажи как отправляешь, может быть на самом деле и не отправляется все? Результат SendBuf анализируешь?
← →
Dmitriy Polskoy (2002-11-13 15:47) [17]Отправляю так
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);
ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
sum := sum + bytesread;
label1.Caption := inttostr(sum);
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;
В Label отображается сколько отослал. На клиенте в Label - сколько принял. Значения не равны. Принятый файл действительно равен кол-ву байт, отображенном в label на клиенте, но ясное дело он битый.
← →
F1 (2002-11-13 15:53) [18]Конечно, проблема именно здесь!!!
ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
Может не послать!!! Он возврвщает количество на самом деле посланных или -1 при ошибке!!!
так что
sum := sum + ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
более реальная цифра, ты ее посмотри, тогда станет ясно, где ошибка!!!
← →
Dmitriy Polskoy (2002-11-13 16:01) [19]Получается, что отсылает меньше, чем принимает. И как сделать, чтобы ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead) все правильно посылал.
← →
F1 (2002-11-13 16:08) [20]Отсылает меньше, чем принимает??? Опять чудеса!!!
Посмотри SendStream, Digitman его советовал использовать.
А если SendBuf, то посылать, пока в буфере есть место, и обрабатывать OnWrite.
Лучше поищи ветку, где Digitman все расписал, там тема была "Как правильно..." или что-то типа того.
← →
F1 (2002-11-13 16:22) [21]Так ведь рядом ветка!
← →
Dmitriy Polskoy (2002-11-13 18:29) [22]procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
res: integer;
begin
BytesRead := Socket.ReceiveLength;
Res := Socket.ReceiveBuf(Buffer, BytesRead);
if Res < BytesRead then ShowMessage("Error");
BlockWrite(DestFile, Buffer, BytesRead, BytesWritten);
end;
У меня выскакивает мое сообщенние в ShowMessage. Как исправить ошибку?
← →
Dmitriy Polskoy (2002-11-13 18:33) [23]2 Digitman © (13.11.02 15:01)
А кусочком кода можно?
← →
stikriz (2002-11-13 19:49) [24]Res := Socket.ReceiveBuf(Buffer, BytesRead);
if Res < BytesRead then ShowMessage("Error");
BlockWrite(DestFile, Buffer, BytesRead, BytesWritten);
end;
Это полный бред. BytesRead - это для того, чтобы не сделать буфер меньше, чем нужно, а Res - это реально скачанные данные. Часто, но не всегда они равны. И никакой ошибки нет, что Res меньше.
Николай.
← →
s002156Shurik (2002-11-14 01:11) [25]Я принимаю так
if Socket.Connected then
begin
if Socket.ReceiveLength>0 then
rsz:=Socket.ReceiveBuf(buf,1024);
end;
понятно дело в цикле вернее в потоке но в данном случае это непринципиально rsz число реально принятых байт проверяю receivelength для того чтобы незапнуться при неожиданном дисконекте если в течении 10 секунд приходят пустые пакеты считаю разрывом по таймауту.
отправляю так:
при коннекте клиента определяю идентификатор сокета
SocHnd:=Socket.SocketHandle;
затем в потоке отсылаю данные через него тыже отсылаеш через конекшенс 0 что будет работать только если один клиент, стемже успехом при коннекте можеш использовать сокетом который передан в ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
и вешать свой сервер на одной задаче. а какже остальные клиенты? или по очереди?
Вобщем я в потоке перебираю все конекшенсы на предмет совпадения идентификатора сокета. и передаю нужному клиенту нужные данные.
for i:=0 to Form1.ServerSocket1.Socket.ActiveConnections-1 do
if Form1.ServerSocket1.Socket.Connections[i].SocketHandle=SoсHnd then
Form1.ServerSocket1.Socket.Connections[i].SendBuf(buf,1024);
простейший способ созданя много потокового сервера файлов это написание объекта на основе TTimer в который при рождении закинуть хандл сокета конекшенса и имя предаваемого файла а дальше запустить OnTime в котором он будет пересылать файл указанным выше способом.
Рождать такой объект нужно при коннекте клиент.
MyTimer:=TMyTimer.create(nil);
MyTimer.FileName:=Socket.recivetext;
MyTimer.SocHnd:=SocHnd:=Socket.SocketHandle;
MyTimer.Interval:=1;
MyTimer.enable:=true;
в OnTime первый раз открыть файл когда он закончится закрыть его
потом сделать дисконнект
for i:=0 to Form1.ServerSocket1.Socket.ActiveConnections-1 do
if Form1.ServerSocket1.Socket.Connections[i].SocketHandle=SoсHnd then
Form1.ServerSocket1.Socket.Connections[i].Disconnect(SocHnd);
и сделать
MyTimer.free;
все.
надеюсь поможет удачи.
← →
Dmitriy Polskoy (2002-11-14 09:23) [26]2 stikriz (13.11.02 19:49)
Ни какой не бред. Если Res меньше, то остальные байты теряются. Мне надо сделать так, как говорит Digitman © (13.11.02 15:01), но я чето туплю и незнаю как это сделать.
2 s002156Shurik © (14.11.02 01:11)
Это не решает проблемы. Ну буду я получать в таймере, а сокет будет записывать меньше, чем получил. Смотри Digitman © (13.11.02 15:01)
← →
Dmitriy Polskoy (2002-11-14 09:57) [27]Я делаю так, но что-то не работает
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
Res: integer;
begin
BytesRead := Socket.ReceiveLength;
Res := Socket.ReceiveBuf(Buffer, BytesRead);
BlockWrite(DestFile, Buffer, Res, BytesWritten);
BytesRead := BytesRead - Res;
while (BytesRead > 0) do
begin
FillChar(Buffer, SizeOf(Buffer), 0);
Res := Socket.ReceiveBuf(Buffer, BytesRead);
BlockWrite(DestFile, Buffer, Res, BytesWritten);
BytesRead := BytesRead - Res;
end;
end;
← →
Dmitriy Polskoy (2002-11-14 10:13) [28]Еще пробовал так
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
Res, LastPos, Temp: integer;
begin
BytesRead := Socket.ReceiveLength;
Temp := BytesRead;
Res := Socket.ReceiveBuf(Buffer, BytesRead);
BytesRead := BytesRead - Res;
while (BytesRead > 0) do
begin
LastPos := LastPos + Res;
Res := Socket.ReceiveBuf(Buffer[LastPos+1], BytesRead);
if Res = -1 then Res := 0;
BytesRead := BytesRead - Res;
end;
BlockWrite(DestFile, Buffer, Temp, BytesWritten);
end;
← →
Digitman (2002-11-14 10:25) [29]
var
TotalBytesRead : Integer = 0;
Buffer : Pointer;
...
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
ActualBytesRead: Integer;
BytesRemainsToRead : Integer;
temp_bufptr: PChar;
begin
if ReceiveLength = 0 then Exit;
BytesRemainsToRead := 500 - TotalBytesRead;
temp_bufptr := Buffer;
Inc(temp_bufptr, TotalBytesRead);
ActualBytesRead := Socket.ReceiveBuf(temp_bufptr^, BytesRemainsToRead);
if ActualBytesRead >= 0 then
begin
Inc(TotalBytesRead, ActualBytesRead);
if TotalBytesRead = 500 then
begin
BlockWrite(DestFile, Buffer, TotalBytesRead,BytesWritten);
TotalBytesRead := 0;
end;
end;
← →
Dmitriy Polskoy (2002-11-14 10:38) [30]А помоги с сервером. Я делаю так, но иногда сервер передает неправильное кол-во байт.
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Res, LasrPos: Integer;
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);
while (Res = -1) do
begin
Sleep(1);
Res := ServerSocket.Socket.Connections[0].SendBuf(Buffer, BytesRead);
end;
sum := sum + Res;
label1.Caption := inttostr(sum);
until BytesRead = 0;
finally
CloseFile(SrcFile);
end;
end;
← →
Digitman (2002-11-14 10:50) [31]Обратись к <V_Pavel>
Устал я уже писать одно и тоже.
Не далее как вчера он получил мылом работающий вариант передатчика с использованием SendStream.
← →
Dmitriy Polskoy (2002-11-14 10:53) [32]2 Digitman © (14.11.02 10:25)
Не, не работает
> if ReceiveLength = 0 then Exit;
По-моему надо Socket.ReceiveLength
> BlockWrite(DestFile, Buffer, TotalBytesRead,BytesWritten);
>
А где же заполняется буфер
И что-то вообще не очень понятно. Если можешь объясни, а?
← →
Dmitriy Polskoy (2002-11-14 10:58) [33]2 Digitman © (14.11.02 10:50)
Да написал я ему, а он молчит. Ну хоть ты не молчи.
← →
Digitman (2002-11-14 11:01) [34]
> По-моему надо Socket.ReceiveLength
Ну надо так надо. Несущественные ляпы сам исправляй.
> А где же заполняется буфер
А это что - по-твоему ?
ActualBytesRead := Socket.ReceiveBuf(temp_bufptr^, BytesRemainsToRead);
> И что-то вообще не очень понятно
Что непонятно ? Конкретно ?
← →
Digitman (2002-11-14 11:06) [35]>Dmitriy Polskoy
Обратись к нему в форуме. Вообще-то я просил его выложить основные элементы программного решения на сайт.
← →
Dmitriy Polskoy (2002-11-14 11:10) [36]2 Digitman © (14.11.02 11:01)
В таком случае надо
Buffer := temp_bufprt, а у тебя наоборот, или я, что-то не так понимаю.
← →
Digitman (2002-11-14 11:19) [37]
> Buffer := temp_bufprt
Зачем ?
temp_bufptr := Buffer; // получить указательна начало буфера
Inc(temp_bufptr, TotalBytesRead); // прибавить смещение
← →
Dmitriy Polskoy (2002-11-14 11:39) [38]2 Digitman © (14.11.02 11:19)
Согласен
А помоги сервером, а то не получается никак. См. Dmitriy Polskoy © (14.11.02 10:38)
← →
Digitman (2002-11-14 12:15) [39]
> не получается никак.
Что не получается ?
← →
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.66 MB
Время: 0.01 c