Форум: "Сети";
Текущий архив: 2003.11.27;
Скачать: [xml.tar.bz2];
ВнизПриём команд/файлов Найти похожие ветки
← →
delpher_gray (2003-09-29 12:27) [0]Я написал вот такой код:
procedure TMain.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
label
StreamReceiving,
EndReceiving;
var
Section, CMD: Char; // Section, command
Buf: PChar; // Receive buffer
RLen: integer; // Receive buffer length
Receive: integer; // Size of receive buffer
begin
RLen := Socket.ReceiveLength;
GetMem(Buf, RLen);
Receive := Socket.ReceiveBuf(Buf^, RLen);
if StreamReceive then
begin
if MS.Size < Size then
begin
StreamReceiving:
if Receive > 0 then
MS.Write(Buf^, RLen);
ProgressBar1.Position := MS.Size * 100 div Size;
Label4.Caption := IntToStr(MS.Size);
if MS.Size >= Size then
goto EndReceiving;
end else
begin
EndReceiving:
MS.SetSize(Size);
//LoadFilesList;
StreamReceive := false;
MS.SaveToFile("ms.txt");
MS.Clear;
Size := 0;
ProgressBar1.Position := 0;
end;
end else
begin
if Receive > 0 then
begin
Section := Buf[0];
CMD := Buf[1];
case Section of
"0": // Files operations
case CMD of
"0": // Files list
begin
Size := StrToInt(Copy(Buf, 3, Pos(#13#10, Buf) -3));
Label3.Caption := IntToStr(Size);
StreamReceive := true;
goto StreamReceiving;
end;
end;
end;
end;
end;
FreeMem(Buf);
end;
Это код клиента, клиент принимает команды типа: 001024, где 00 - команда, а всё остальное размер файла...
Пока клиент принимеает только одну команду, но позже сделаю коман намного больше...
Так вот такая проблема: я записываю полученные данные в переменную Buf (PChar), а затем в MemoryStream. Как только скачался весь файл, MemoryStream сохраняется на диске.
В файле получается содержание такого типа:
001024
Код файла
Как мне избавиться от команды ? То есть чтоб в файл записывался только код посылаемого файла ?
И ещё... Подскажите правильно ли я написал программу ? Не нужли что-нибудь в ней срочно менять ?
Заранее благодарен.
← →
Digitman (2003-09-29 13:04) [1]на основании что ты столь верен, что при первом же событии OnRead клиент получит упомянутый префикс "001024" целиком ? А если при первом OnRead придет "0" и лишь при следующем OnRead - все остальное (т.е. "01024") ?
куда пойдет обращение buf[1], если в буфере в этот момент всего 1 байт ?
← →
delpher_gray (2003-09-29 15:24) [2]2Digitman:
Ээээ...
Об этом я не подумал.....
Сделаю !
А ещё есть ошибки ??
И сам вопрос был как вырезать из буфера всё до "#13#10" ?
← →
Digitman (2003-09-29 15:47) [3]а и "вырезать" ничего не надо ... да и зачем вообще <CR><LF> передавать ? измени протокол обмена так, чтобы передающая сторона передавала префикс заранее известного принимающей стороне размера (например, 8 байт : КОП (intrger) + DataSize(Integer))
изначально приним.сторона находится в ожидании приема префикса.
пока она не примет в буфер (за одно или несколько событий OnRead) префикс целиком (т.е. 8 байт), ни о каком последующем приеме файловых данных не может быть и речи
как только префикс принят, идет анализ его КОП (первые 4 байт) и DataSize (следующие 4 байт). Если рез-ты анализа в порядке, приним.сторона переключается в режим ожидания/приема данных, которые опять же за одно или несколько событий OnRead будут каждый раз считываться тобой во врем. буфер и тут же записываться в накопительный поток. Ждать и обрабатывать события в этом режиме следует до тех пор, пока накоп.поток не примет размер, равный ожидаемому (в соответствии с принятым ранее префиксом) размеру DataSize
всех делов)
← →
delpher_gray (2003-09-29 15:57) [4]Ну а если пакеты склеятся ?
Тогда:
001024
Код файла....
Как сделать нормальный приём префикса, я после первого ответа поянл... А вот как отделить префикс от файла ???????
← →
Digitman (2003-09-29 16:59) [5]
> Ну а если пакеты склеятся ?
какие еще "пакеты" ?!
ты ждешь 8 байт префикса ? ну и жди их ! ровно 8 байт ! ни больше и не меньше ! зачем считывать в событии OnRead все пришедшее, если тебе требуется всего 8 байт ?
type
TPrefix = packed record
OPCode: Integer;
DataSize: Integer;
end;
PPrefix = ^TPrefix;
var
buf: array[0..4095] of byte;
Prefix: TPrefix;
PrefixOffset : Integer;
DataSize : Integer;
...
режим = прием_префикса;
Offset := 0;
buf := @Prefix;
.....
procedure Объект.OnRead(...);
var
BytesRead: Integer;
begin
if режим = прием_префикса then
begin
BytesRead = Socket.ReceiveBuf(buf[Offset], SizeOf(Prefix) - Offset);
Inc(Offset, BytesRead);
if Offset = SizeOf(Prefix) then
begin
DataSize := PPrefix(@buf)^.DataSize;
режим = прием_данных;
end;
end
else
begin
BytesRead = Socket.ReceiveBuf(buf, Min(DataSize, SizeOf(buf));
запись_BytesRead_байт_из_буфера_в_накопительный_поток;
Dec(DataSize, BytesRead);
if DataSize = 0 then
begin
...
режим := прием_префикса;
Offset := 0;
end;
end;
end;
← →
delpher_gray (2003-09-30 15:50) [6]Млин...
У меня префикс может быть любой длины (до симвова #13#10) !!
← →
Digitman (2003-09-30 16:07) [7]а на кой черт он вообще у тебя текстовый , префикс-то ?
а уж если текстовый, то вместо #13#10 в конце строкового префикса передавай ПЕРЕД ним 4 байта (Integer), значение которых известят принимающую сторону о длине следом передаваемых строковых данных, являющих собой префикс
← →
Digitman (2003-09-30 16:11) [8]можно и 2-мя байтами (Word) обойтись (те же самые #13#10 по размеру получается), если длина стр.данных в префиксе не превышает MAX_WORD
← →
delpher_gray (2003-10-01 13:32) [9]Всё.. Понял...
Всё заработало !
Digitman ! Не мог бы ты объяснить алогоритм работы ??
Я не до конца понимаю (Dec, Min, PPrefix(@buf)^, и т.д....)
← →
Digitman (2003-10-01 14:05) [10]
> Dec(DataSize, BytesRead);
вычесть из значения переменной DataSize (хранящей полный размер ожидаемых на этот момент данных) значение переменной BytesRead (куда метод ReceiveBuf только что записал размер очередной принятой "порции" этих ожидаемых данных)
> BytesRead = Socket.ReceiveBuf(buf, Min(DataSize, SizeOf(buf));
попытаться прочитать в буфер Buf порцию ожидаемых данных размера, указанного в DataSize, но не более чем размер буфера (т.е. максим.размер считываемой за один прием порции данных не должен превышать размер буфера, иначе при записи в буфер произойдет выход за границы памяти, отведенные под него)
> DataSize := PPrefix(@buf)^.DataSize;
поскольку буфер представлен в памяти статически и имеет тип array[..] of byte, а содержимое этого буфера в дан.момент есть целиком принятая префиксная структура, то для того чтобы обратиться к полю DataSize этой структуры, мы должны на время представить адрес буфера как указатель на структуру, после чего к полю структуры можно обращаться обычным привычным образом - по имени поля
@buf - компилятор вычисляет адрес буфера
PPrefix(@buf) - "успокаиваем" компилятор, говоря ему , что мы осознанно пытаемся рассматривать в дан.момент адрес буфера как указатель на некую структуру TPrefix
PPrefix(@buf) ^.DataSize - делаем т.н. "разыменование" (в принципе - необязательное в этом контексте, потому что компилятор и без этого поймет, что от него требуется, но зато более наглядное), в рез-те чего получаем значение указателя типа PPrefix ... а указывает он на данные типа TPrefix ... после чего просто обращаемся к полю TPrefix.DataSize по чтению, копируя его содержимое в лок.переменную для дальнейшей работы ... ибо в режиме "прием_данных" новое содержимое буфера затрет старое, хранившее в режиме "прием_префикса" частично или полностью принятый префикс ... кстати не забудь сохранить и поле OPCode для дальн.анализа !
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2003.11.27;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.009 c