![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с компонентами TidTCPServer и TidTCPClient [D7, WinXP]
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);вообще не пойму что происходит.. отправляем окну сообщение - это понятно, а что в параметрах?..