Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблема с компонентами TidTCPServer и TidTCPClient [D7, WinXP]


Страницы:   1 2 3

maxistent ©   (2009-11-30 06:57:00) 

Доброго времени суток. Подскажите как правильно использовать компоненты TidTCPServer и TidTCPClient для передачи данных? На сервере в OnExecute можно просто сделать что-то вроде AThread.Connection.ReadBuffer(Data,DataSize)? или надо как-то по-особому обрабатывать этот эвент? Собственно проблема вот в чем: пишу софт для передачи картинки с экрана в реалтайме (ну или почти в реалтайме). Получилось что-то вроде этого:

с клиента передаю данные idTcpClient1.WriteBuffer(...);

на сервере принимаю так:


procedure TForm1.ss1Execute(AThread: TIdPeerThread);
var
buf1,buf2:pointer;
DataSize:integer;
st:TStream;
jpg:TJPEGImage;
r:TRect;
begin
AThread.Connection.ReadBuffer(DataSize,sizeof(DataSize));
AThread.Connection.ReadBuffer(r,sizeof(r));
GetMem(buf1,DataSize);
AThread.Connection.ReadBuffer(buf1^,DataSize);
st:=TMemoryStream.Create;
st.Write(buf1^,DataSize);
FreeMem(buf1,DataSize);
st.Position:=0;
jpg:=TJPEGImage.Create;
jpg.LoadFromStream(st);
st.Free;
image1.Picture.Bitmap.Canvas.draw(r.Left,r.Top,jpg);
jpg.Free;
end;


При подключении начинается передача изображения, но через несколько секунд (~5 сек) изображение перестает обновляться, а еще через несколько секунд прога "вылетает" с сообщением <Canvas does not allow drawing>. что здесь не так? не могу понять...


Slym   (2009-12-02 11:33:00) [1]

http://www.delphimaster.ru/cgi-bin/forum.pl?id=1227604925&n=4


maxistent   (2009-12-01 14:35:00) [2]

ну это я уже по памяти списывал из кода и "на лету" редактировал, чтоб вам было проще читать... там не "ptrDataToRender", а "buf"  =)


CrytoGen   (2009-12-01 13:49:00) [3]

не походу ты всё равно не внимательно к указателям относишься:
try
PostMessage(Form1.Handle, WM_DATA_TO_RENDER_AVAIL, WPARAM(buf), LPARAM(DataSize)); except
FreeMem(ptrDataToRender);
raise;
end;

где ты тут работал с ptrDataToRender?


maxistent   (2009-12-01 13:46:00) [4]

p.s. в [40] последние 6 строк кода ошибочно вставлены...


maxistent   (2009-12-01 13:42:00) [5]

в общем, я сделал так:

procedure TForm1.ss1Execute(AThread: TIdPeerThread);
var
buf:pointer;
DataSize:integer;
st:TStream;
r0:TRect;
p0:TPoint;
begin
AThread.Connection.ReadBuffer(p0,sizeof(p0));//"габариты" всей картинки
AThread.Connection.ReadBuffer(r0,sizeof(r0));//позиция текущего фрагмента
AThread.Connection.ReadBuffer(DataSize,sizeof(DataSize));//размер изображения (jpg)
GetMem(buf,DataSize);
AThread.Connection.ReadBuffer(buf^,DataSize);

//тут я все это складываю в стрим...
st:=TMemoryStream.Create;
st.Write(p0,sizeof(p0));
st.Write(r0,sizeof(r0));
st.Write(buf^,DataSize);
FreeMem(buf,DataSize);
st.Position:=0;
//потом читаю это все в память...
DataSize:=st.Size;
GetMem(buf,DataSize);
st.Read(buf^,DataSize);
st.Free;

//и передаю дальше...
try
 PostMessage(Form1.Handle, WM_DATA_TO_RENDER_AVAIL, WPARAM(buf), LPARAM(DataSize)); except
 FreeMem(ptrDataToRender);
 raise;
end;
end;

procedure TForm1.WMMyMessage(var Message: TMessage);
var
ptrDataToRender: Pointer;
dwSizeOfDataToRender: DWord;
st:TStream;
jpg:TJPEGImage;
p:TPoint;
r:TRect;
begin
ptrDataToRender := Pointer(Message.wParam);
dwSizeOfDataToRender := DWord(Message.lParam);
try
st:=TMemoryStream.Create;
st.Write(ptrDataToRender^,dwSizeOfDataToRender);
st.Position:=0;
st.Read(p,sizeof(p));
st.Read(r,sizeof(r));
jpg:=TJPEGImage.Create;
jpg.LoadFromStream(st);
st.Free;:=TJPEGImage.Create;
jpg.LoadFromStream(st);
st.Free;
Image1.Picture.Bitmap.Canvas.Draw(r.Left,r.Top,jpg);
jpg.Free;
finally
 FreeMem(ptrDataToRender);
end;
end;
Image1.Picture.Bitmap.Canvas.Draw(r.Left,r.Top,jpg);
jpg.Free;
finally
 FreeMem(ptrDataToRender);
end;
end;


Теперь все безупречно работает. И память распределяется и расходуется вроде правильно. Большое спасибо вам всем! теперь буду внимательней "смотреть" на указатели.. =)


Сергей М.   (2009-12-01 13:33:00) [6]

> в каком месте нужно выполнять FreeMem(ptrDataToRender);?

Минимум в 2-х:

1. на стороне отправителя - при исключении.
2. На стороне получателя - безусловно.


CrytoGen   (2009-12-01 13:20:00) [7]

вообще странный код:
ptrDataToRender := SysGetMem(DataSize);
try
 CopyMemory(buf, ptrDataToRender, DataSize);
 PostMessage(Form1.Handle, WM_DATA_TO_RENDER_AVAIL, WPARAM(ptrDataToRender), LPARAM(DataSize)); except
 FreeMem(ptrDataToRender);
 raise;
end;
FreeMem(buf1,DataSize);


что за buf1?
почему raise?

FreeMem правильно написан
finally
 FreeMem(ptrDataToRender);
end;


maxistent   (2009-12-01 13:06:00) [8]

сорри, по поводу п.2 это я протупил. да, действительно перепутал. сейчас поменял местами - то же самое. в каком месте нужно выполнять FreeMem(ptrDataToRender);?


Сергей М.   (2009-12-01 12:59:00) [9]

> в чем моя ошибка?

Их минимум две:

1. Собственноручно уничтожил только что принятые данные, см. [33]
2. Поменял местами источник и приемник в операции копирования (CopyMemory), указав к тому же в кач-ве приемника адрес уже не существующего буфера, который ты см. п.1


maxistent   (2009-12-01 12:55:00) [10]

что? где? в чем моя ошибка? я понимаю (во всяком случае подозреваю), что с указателями что-то напутал, но где именно - не могу понять


Сергей М.   (2009-12-01 12:53:00) [11]


> CopyMemory(buf, ptrDataToRender, DataSize);


Это что за ерунда ?!
Да еще и с учетом [33] ?


CrytoGen   (2009-12-01 12:45:00) [12]

молодец
 FreeMem(ptrDataToRender);


maxistent   (2009-12-01 12:39:00) [13]

ну вот такой у меня код:

procedure TForm1.ss1Execute(AThread: TIdPeerThread);
var
buf:pointer;
DataSize:integer;
st:TStream;
r0:TRect;
p0:TPoint;
ptrDataToRender:Pointer;
begin
AThread.Connection.ReadBuffer(p0,sizeof(p0));//"габариты" всей картинки
AThread.Connection.ReadBuffer(r0,sizeof(r0));//позиция текущего фрагмента
AThread.Connection.ReadBuffer(DataSize,sizeof(DataSize));//размер изображения (jpg)
GetMem(buf,DataSize);
AThread.Connection.ReadBuffer(buf^,DataSize);

//тут я все это складываю в стрим...
st:=TMemoryStream.Create;
st.Write(p0,sizeof(p0));
st.Write(r0,sizeof(r0));
st.Write(buf^,DataSize);
FreeMem(buf,DataSize);
st.Position:=0;
//потом читаю это все в память...
DataSize:=st.Size;
GetMem(buf,DataSize);
st.Read(buf^,DataSize);
st.Free;

//и передаю дальше...
ptrDataToRender := SysGetMem(DataSize);
try
  CopyMemory(buf, ptrDataToRender, DataSize);
  PostMessage(Form1.Handle, WM_DATA_TO_RENDER_AVAIL, WPARAM(ptrDataToRender), LPARAM(DataSize)); except
  FreeMem(ptrDataToRender);
  raise;
end;
FreeMem(buf1,DataSize);
end;

procedure TForm1.WMMyMessage(var Message: TMessage);
var
ptrDataToRender: Pointer;
dwSizeOfDataToRender: DWord;
st:TStream;
jpg:TJPEGImage;
p:TPoint;
r:TRect;
begin
ptrDataToRender := Pointer(Message.wParam);
dwSizeOfDataToRender := DWord(Message.lParam);
try
//дальше я уже не могу ничего сделать - буфер не тот, но в переменной
//dwSizeOfDataToRender значение верное
{ st:=TMemoryStream.Create;
st.Write(ptrDataToRender^,dwSizeOfDataToRender);
st.Position:=0;
st.Read(p,sizeof(p));
st.Read(r,sizeof(r));
jpg:=TJPEGImage.Create;
jpg.LoadFromStream(st);
st.Free;
Image1.Picture.Bitmap.Canvas.Draw(r.Left,r.Top,jpg);
jpg.Free;}
finally
  FreeMem(ptrDataToRender);
end;
end;


brother   (2009-12-01 12:37:00) [14]

ну, партизан... код показывай уже а? что за ё маё?


Сергей М.   (2009-12-01 12:24:00) [15]

У тебя с головой и логикой вообще все в порядке ?)

Ты где-то там накосячил, код ты показывать не желаешь, а я должен догадаться с 3-х раз, где и что у тебя там не так ?)


maxistent   (2009-12-01 12:20:00) [16]

нет, врядли =) в 17-й строке написано TForm1 = class(TForm)
ну а если серьезно? почему данные, полученные обработчиком сообщения (procedure WMMyMessage(var Message: TMessage)) отличаются от тех, которые были изначально ему переданы? отличается именно буфер!


Сергей М.   (2009-12-01 11:59:00) [17]


> что-то тут не так


Угу.
Ошибка у тебя в программе, в 17-й строке)


maxistent   (2009-12-01 11:50:00) [18]

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

> ptrDataToRender := Pointer(Message.wParam); // вот тебе
> адрес буфера

вот тут явно не тот буфер (я проверял), который был изначально в OnExecute, хотя dwSizeOfDataToRende имеет правильное значение. что-то тут не так..


Сергей М.   (2009-12-01 09:46:00) [19]


> что есть ptrDataReadFromClient?


Указатель на очередной блок данных, полученный сервером от клиента в теле OnExecute.


> что за сообщение такое WM_DATA_TO_RENDER_AVAIL?


Константа-идентификатор предопределенного тобой пользовательского сообщения, например, WM_USER + 1000


> что в этом блоке кода происходит


Очередной блок данных, который твой сервер получил в OnExecute от клиента и который должен быть отрисован формой в осн.потоке, копируется в подготовленный (выделением памяти) буфер, указатель на этот буфер передается параметром wParam асинхронного сообщения окну твоей формы.

В классе твоей формы, соотв-но, должен быть предусмотрен обработчик этого сообщения, в теле которого данные по переданному в сообщении адресу можно безопасно рисовать куда тебе вздумается

В OnExecute:

var
ptrDataToRender: Pointer;
..
ptrDataToRender := SysGetMem(dwBytesReadFromClient);
try
  CopyMemory(ptrDataReadFromClient, ptrDataToRender, dwBytesReadFromClient);
  PostMessage(MyRenderForm.Handle, WM_DATA_TO_RENDER_AVAIL, WPARAM(ptrDataToRender), LPARAM(dwBytesReadFromClient));
except
   FreeMem(ptrDataToRender);
   raise;
end;

В юните формы:

const
 WM_DATA_TO_RENDER_AVAIL = WM_USER + 1000;
..
TMyForm = class(TForm)
...
private
..
 procedure WMMyMessage(var Message: TMessage); message WM_DATA_TO_RENDER_AVAIL;
..
end;
..
procedure TMyForm.WMMyMessage(var Message: TMessage);
var
 ptrDataToRender: Pointer;
 dwSizeOgDataToRender: DWord;
begin
 ptrDataToRender := Pointer(Message.wParam); // вот тебе адрес буфера
 dwSizeOgDataToRender := DWord(Message.lParam); //вот тебе размер данных в этом буфере
 try
.. тут обрабатывай его как угодно - хоть рисуй его где хочешь, хоть еще что-то ..
 finally
   FreeMem(ptrDataToRender); // и обязательно освободи память, выделенную в OnExecute под этот буфер !!
 end;
end;


maxistent   (2009-12-01 09:45:00) [20]

вопросы:
1) WM_DATA_TO_RENDER_AVAIL - это, как я понимаю, МОЕ СОБСТВЕННОЕ сообщение, так? тогда как его обработать потом?
2) в строке PostMessage(MyRenderForm.Handle, WM_DATA_TO_RENDER_AVAIL, Pointer(dwBytesReadFromClient), Self);вообще не пойму что происходит.. отправляем окну сообщение - это понятно, а что в параметрах?..


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо