![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Непонятная проблема с буфером в Инди компоненте [D7, WinXP]
h0use © (2003-11-24 15:32:00)
Есть сервер, который слушает порт:
Msg:=AThread.Connection.ReadLn;
if Msg<>">>>" then exit;
AThread.Connection.ReadBuffer(CommBlock,SizeOf(CommBlock));
Есть клиент, котрый шлет на сервер блок данных:
function TfmMain.SendMsg(AMsg:TCommBlock): boolean;
begin
Result:=False;
try
if TCPClient.Connected then
begin
TCPClient.WriteLn(">>>");
TCPClient.WriteBuffer(AMsg,SizeOf(AMsg));
Result:=True;
end;
except
on e: Exception do
ShowMessage("Send Error: "+e.Message);
end; // try/except
Есть сам покет данных одинаковый для сервера и клиента:
type
TCommBlock = record // the Communication Block used in both parts (Server+Client)
Command : Char;
Argument1 : String[10];
Argument2 : WideString;
Msg : WideString;
end;
При том, что при дебаге клиент шлет нормальную инфу, сервер получает тольуо первый и второй аргумент записи нормально, а третий и четвертый - белеберда. В чем ботва?
h0use (2003-11-25 17:19:00) [1]
Просто провал в образовании, я всегда считал, что если у строки не указано кол-во символов, то это эквивалентно строке 255 символов т.е. String=String[255]. Оказалось что заблуждался, хоть и в хелпе не нашел информации.
Reindeer Moss Eater (2003-11-25 17:11:00) [2]
Что "все"?
У тебя и так все работает.
Все что ты просишь у компилятора.
Он создает отличный код, который передает ВСЕ, что ты его просишь передать (все до единого бита)
И пора понять, что есть короткие строки, все символы которых лежат внутри записи, и есть длинные строки, которые находятся в куче. И куча эта располагается далеко за пределами всех сегментов твоей программы (кода,данных,стека)
h0use (2003-11-25 17:09:00) [3]
Забыл поблагодарить за помощь!
h0use (2003-11-25 17:09:00) [4]
И заработало! Блин, но так не честно! Нигде в хелпе по Делфе это не написано, а я угробил сутки для понимания проблемы :(
h0use (2003-11-25 17:06:00) [5]
т.е. если я напишу String[255] то все заработает?
Reindeer Moss Eater (2003-11-25 17:04:00) [6]
Потому что там компилятор считает Msg короткой строкой.
h0use (2003-11-25 16:57:00) [7]
Ну так объясните, плиз, если у меня конструкция
TCommBlock = packed record
Command : Byte;
Argument1 : Byte;
Argument2 : Byte;
Msg : String;
end;
И почему при аналогичной структуре в примерах Инди все работает без ухищрения с указателями?
Reindeer Moss Eater (2003-11-25 16:07:00) [8]
Очевидно, что правильно будет тогда, когда не будешь на очередном шаге портить содержимое памяти созданное предыдущим шагом.
А вообще тот конкретный пример был дан как иллюстрация передачи конкретной структуры. Её не предлагалось изменить, а была предложена подпорка, которая умеет передавать данные той первоначальной структуры.
h0use (2003-11-25 16:01:00) [9]
Ну так а как сделать правильно?
Reindeer Moss Eater (2003-11-24 17:17:00) [10]
//Распределил память под сообщение
GetMem(p,SizeOf(Char)+3*SizeOf(Cardinal)+StrLen(AMsg.Argument1)+StrLen(AMsg.Argument2)+StrLen(AMsg.Msg));
//Записал символ команды
pC:=p;
pC^:=AMsg.Command;
Inc(pC);
//После символа команды записал длину первого аргумента
pLen1 := Pointer(pC);
pLen1^:=StrLen(AMsg.Argument1);
//После длины первого аргумента записал строку первого аргумента
Inc(PLen1);
StrCopy(PChar(PLen1),AMsg.Argument1);
//Встал на начало строки первого аргумента
pLen2 := Pointer(pLen1);
//Испортил первые четыре символа строки первого аргумента, записав поверх их длину второго аргумента
pLen2^:=StrLen(AMsg.Argument2);
Inc(PLen2);
//Перешагнул через испорченные 4 первых байта строки первого аргумента и записал строку второго аргумента (поверх еще неиспорченных символов строки первого аргумента)
StrCopy(PChar(PLen1),AMsg.Argument2);
....
Ну и так далее
h0use (2003-11-24 17:14:00) [11]
Впринципе логично, можно и не использовать...буду думать дальше...
sanya-spb (2003-11-24 17:05:00) [12]
а зачем тебе так надо открытые строки использовать?
неужели нельзя ShortString взять?
если нельзя то можно заменить строку на StringStream или нечто подобное...
h0use (2003-11-24 16:56:00) [13]
Делаю вот так:
GetMem(p,SizeOf(Char)+3*SizeOf(Cardinal)+StrLen(AMsg.Argument1)+StrLen(AMsg.Argument2)+StrLen(AMsg.Msg));
pC:=p;
pC^:=AMsg.Command;
Inc(pC);
pLen1 := Pointer(pC);
pLen1^:=StrLen(AMsg.Argument1);
Inc(PLen1);
StrCopy(PChar(PLen1),AMsg.Argument1);
pLen2 := Pointer(pLen1);
pLen2^:=StrLen(AMsg.Argument2);
Inc(PLen2);
StrCopy(PChar(PLen1),AMsg.Argument2);
pLen3 := Pointer(pLen2);
pLen3^:=StrLen(AMsg.Msg);
Inc(PLen3);
StrCopy(PChar(PLen1),AMsg.Msg);
TCPClient.WriteLn(">>>");
TCPClient.WriteBuffer(p^,SizeOf(Char)+3*SizeOf(Cardinal)+StrLen(AMsg.Argument1)+StrLen(AMsg.Argument2)+StrLen(AMsg.Msg)) ;
Result:=True;
Пришлось поменять в структуре все виды срок на PChar, так как я не додумался как адаптировать пример по ссылке под widestring, но все равно не работает!
Reindeer Moss Eater (2003-11-24 16:51:00) [14]
В качестве того же указателя, но "в профиль" ?
sanya-spb (2003-11-24 16:49:00) [15]
как вариант может и PChar сойти.. я так думаю
Digitman (2003-11-24 16:35:00) [16]
> я слабо понял
это печально
и не поймешь, пока не бросишь слепые эксперименты и не обратишься к соотв.литературе ... либо не начнешь задавать КОНКРЕТНЫЕ вопросы, мол, объясните . почему это именно так , а не иначе
Reindeer Moss Eater (2003-11-24 16:29:00) [17]
Тогда просто замени свои WideString на ShortString
h0use (2003-11-24 16:27:00) [18]
Если честно, то я слабо понял, что там происходит (в примере по ссылке)
Digitman (2003-11-24 16:05:00) [19]
> h0use
> как же мне их передавать
как компилятор хранит - так и передавай : сначала размер, потом данные
Reindeer Moss Eater (2003-11-24 16:00:00) [20]
А ссылка для кого вообще приведена была?