Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.11.12;
Скачать: [xml.tar.bz2];

Вниз

Проблемы при работе с Indy   Найти похожие ветки 

 
Сергей М. ©   (2006-09-11 10:21) [80]


> Только для этого задействовать буфер..


Что значит "задействовать" ? Он и так задействован в TIdTCPConnection, хочешь тыт того или нет...


> Затем преобразовывать строку в цепочку байтов - неэффективно.
>
> Да и внутренний буфер опять задействовать придётся...


Это еще зачем ?

s := AThread.Connection.CurrentReadBuffer;
if Length(s) > 0 then
 AThread.Connection.WriteBuffer(PChar(s)^, Length(s));


 
Cyrax ©   (2006-09-11 20:07) [81]

Что значит "задействовать" ? Он и так задействован в TIdTCPConnection, хочешь тыт того или нет...

(типа "да-да", "ну-ну" не буду...:) )
По моему, буфера, с которыми работает Connection, - это вовсе не InputBuffer. Причём InputBuffer - только для удобства вывода.
И для работы с InputBuffer его нужно проинициализировать (кажется, Connection.CreateBuffer или что-то типа того).

s := AThread.Connection.CurrentReadBuffer;
if Length(s) > 0 then
AThread.Connection.WriteBuffer(PChar(s)^, Length(s));

А string в Delphi - не объект ?.. чтобы его PChar"ить...
А первым параметром WriteBuffer"а может быть чистый адрес?

И вот ещё два таких вопроса возникло.
1. Что за буфер нужен методу ReadBuffer класса TMemoryStream (первый параметр)? Как в Connection.ReadBuffer не прокатывает. А там у меня массив byte"ов. Передаю имя массива. Pointer проглатывает.
1.5. А нужно мне прочитать в TMemoryStream. Пытаюсь как-то с MemoryStream.Memory, но ни в какую...
2. Как можно без вспомогательного локального буфера считать из Connection в MemoryStream ?


 
Сергей М. ©   (2006-09-12 08:33) [82]


> буфера, с которыми работает Connection, - это вовсе не InputBuffer.
>  Причём InputBuffer - только для удобства вывода.
> И для работы с InputBuffer его нужно проинициализировать
> (кажется, Connection.CreateBuffer или что-то типа того).
>


Ну ты бы хоть в исходники заглянул, прежде чем рассуждать)...


> string в Delphi - не объект ?


Нет, не объект.


> первым параметром WriteBuffer"а может быть чистый адрес?


Что значит "чистый" ?


> 1. Что за буфер нужен методу ReadBuffer класса TMemoryStream
> (первый параметр)?


Буфером может быть любой блок памяти, так или иначе распределенный в ВАП тек.процесса и доступный по записи.


> Как в Connection.ReadBuffer не прокатывает


Что значит "не прокатывает" ?

Прототипы методов обоих классов абсолютно идентичны.


> у меня массив byte"ов


Любой блок памяти, используемый как буфер, можно интерпретировать как массив байт.


> Передаю имя массива


Массив при этом д.б. статический.


> мне прочитать в TMemoryStream. Пытаюсь как-то с MemoryStream.
> Memory, но ни в какую


MemStream.Size := SomeSize;
Connection.ReadBuffer(MemStream.Memory^, MemStream.Size);


> 2. Как можно без вспомогательного локального буфера считать
> из Connection в MemoryStream ?


Никак.
Промежуточный буфер так или иначе (явно или неявно) используется, без него никак не обойтись.


 
Cyrax ©   (2006-09-12 21:44) [83]

Ну ты бы хоть в исходники заглянул, прежде чем рассуждать)...

Да.. Рассказал сказок...

Буфером может быть любой блок памяти, так или иначе распределенный в ВАП тек.процесса и доступный по записи.

... только передавать его можно не по всякому...
А ВАП - это типа процессоптера ?

MemStream.Size := SomeSize;
Connection.ReadBuffer(MemStream.Memory^, MemStream.Size);

Это же и есть без вспомогательного... (из Connection в MemoryStream)

___________________________
А есть ли в Delphi модули для работы с динамическими очередями - типа C"ных queue.h ?
Нужно для целых.

__________________________
А теперь про TMemoryStream.
Материться не буду. Просто приведу фрагмент кода:

var buf: TMemoryStream;
    int i: integer;
    data: array[0..99] of byte;
begin
 for i := 1 to 99 do data[i] := i;
 buf := TMemoryStream.Create;
 buf.WriteBuffer(data,5);  // всё чисто: size = 5, position = 5
 buf.ReadBuffer(data,5);  // ошибка: stream read error (чтение по такому-то адресу)
                                 // ReadBuffer вызывает Read, который возвращает 0 (число прочитанных байтов),
                                 // из-за чего (count <> 0) генерится ошибка. В Read просунуться не смог - нет исходников...
                                 // Пробовал после создания buf Clear"ить, обнулять Position - то же самое. Пробовал с TStringStream - ошибки нет, но читает 0 символов (т.е. ReadString возвращает "").
 buf.Destroy;
end;

... а дальше можно вешаться... или пристрелиться...


 
Dmitrij_K   (2006-09-12 21:54) [84]


> Просто приведу фрагмент кода

Смотрел плакал
 
 buf := TMemoryStream.Create;
 try
   buf.WriteBuffer(data,5);
   ZeroMemory(@data[0], SizeOf(data));
   buf.Position := 0;
   buf.ReadBuffer(data,5);
   if data[0]=1 then
     sleep(1);
 finally
   buf.Free;
 end



> В Read просунуться не смог - нет исходников

Не надо врать. Classes.pas должен быть


 
Cyrax ©   (2006-09-12 22:17) [85]

Я не идиот !  Это я на сях привык.
А там data - указатель на data[0].
Деструктор - не Free, а что-то вроде Destroy.

ZeroMemory(@data[0], SizeOf(data));

Если это чистка памяти, то почему @data[0], а не data ?

buf.Position := 0;

Create - что, Position не обнуляет ?

Кроме того, с connection"ом мой вариант кода прокатывает без проблем !
А finally и sizeof - не использовал, поскольку фрагмент не из моего модуля, а надуманный, только для анализа етого фокуса...
И почему Free, а не Destroy ?  Деструктор же. Не должен тупить...

if data[0]=1 then
    sleep(1);

А ето шо ?  Особенно sleep ?

И чем мой код принципиально отличается от етого. Глюки были только из-за ZeroMemory ?  Не верится...

Не надо врать. Classes.pas должен быть

Я и не вру. Classes.pas есть. Но там только ReadBuffer имплементится, Read - нет. А дальше (в Read) - не пускают...


 
Dmitrij_K   (2006-09-12 22:35) [86]


> Это я на сях привык.

Тогда простительно :)
ZeroMemory и sleep для проверки данных в отладчике, мусор вобщем
В Classes.pas ищи TCustomMemoryStream.Read

> И почему Free, а не Destroy ?

Так принято в Delphi.
Ошибка в Read потому что ты пытался читать с позиции 5, те вверх а не вниз. Вот и получил AV


 
Сергей М. ©   (2006-09-13 09:09) [87]


> Cyrax ©   (12.09.06 21:44) [83]


> только передавать его можно не по всякому


Разумеется не по-всякому.
Это зависит от того как декларированы формальный и фактический параметры.


> ВАП - это типа процессоптера ?


Это Виртуальное Адресное Пространство (процесса).


> Это же и есть без вспомогательного


А SomeSize тебе с потолка свалился ?


> есть ли в Delphi модули для работы с динамическими очередями
> - типа C"ных queue.h ?
> Нужно для целых.


Есть.
См. класс TQueue в Contnrs.pas


>  buf.WriteBuffer(data,5);  // всё чисто: size = 5, position
> = 5
>  buf.ReadBuffer(data,5);  // ошибка: stream read error


Чтение из стрима всегда осуществляется с тек.позиции в стриме.
А она у тебя в момент попытки чтения указывает на конец стрима, оттого и исключение.


> В Read просунуться не смог - нет исходников


Есть исходники !

cм. TCustomMemoryStream.Read (Classes.pas)


> я на сях привык.
> А там data - указатель на data[0]


И в данном случае тоже самое - 1-м параметром в ReadBuffer() фактически передается адрес data[0]


> почему @data[0], а не data ?


Потому что формальный параметр Destination объявлен как pointer и тербует передачи в кач-ве фактического параметра нач.адреса блока памяти.
А нач.адрес стат.массива data и есть адрес его младшего элемента, т.е. @data[0]

Вот если бы Destination был объявлен как нетипизированный параметр, передаваемый по ссылке (т.е. var Destination или const Destination), факт.параметр data можно было бы передать так как ты привык на Сях:

ZeroMemory(data, sizeof(data));

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


 
Cyrax ©   (2006-09-13 22:11) [88]

Dmitrij_K   (12.09.06 22:35) [86]
В Classes.pas ищи TCustomMemoryStream.Read

Всё чих-пых, только вот в режиме отладки в библиотечные функции не пускают... В release-варианте, наверное, скомпилен (Delphi)...
Да ещё по Ctrl в ReadBuffer пускают, а дальше - в Read (это который от TCustomMemory) - никак...

Блин, я везде в своих классах Destroy вызывал...
(The Destroy destructor should never be called directly. To destroy a component created with Create, call the Free method.)

Сергей М. ©   (13.09.06 09:09) [87]
>> Это же и есть без вспомогательного
>А SomeSize тебе с потолка свалился ?

Это не буфер.

Чтение из стрима всегда осуществляется с тек.позиции в стриме.
А она у тебя в момент попытки чтения указывает на конец стрима, оттого и исключение.

Всё понятно. Мне нужен был поток, который бы при чтении декрементировал position и уменьшал размер. Подобно Connection"у. Оных не нашёл - пришлось наследовать самому...

> почему @data[0], а не data ?
Потому что формальный параметр Destination объявлен как pointer и тербует передачи в кач-ве фактического параметра нач.адреса блока памяти...

Адрес или указатель на этот адрес ?
Я думаю указатель (нетипизированный) на этот адрес (pointer).

Вот если бы Destination был объявлен как нетипизированный параметр, передаваемый по ссылке (т.е. var Destination или const Destination), факт.параметр data можно было бы передать так как ты привык на Сях:
        ZeroMemory(data, sizeof(data));
В этом случае заботу о вычислении нач.адреса блока памяти, распределенного под факт.параметр, берет на себя сам компилятор.

Т.е. data здесь воспринимается не как указатель на первый элемент массива (как в C), а как сам массив, адрес которого ещё нужно вычислить ?

Предположим, я передам data там, где требуется указатель на адрес (pointer). Тогда компилятор возмёт первые 4 байта массива и интерпретирует их как адрес данных, с которыми он будет работать ?

_____________________________________________________________
Кстати, длина статического массива хранится в байтах перед первым элементом массива ?  И сколько байт выделяется под эту длину ?


 
Сергей М. ©   (2006-09-14 09:34) [89]


> Cyrax ©   (13.09.06 22:11) [88]


> Это не буфер


Разумеется.
Это то самое значение, которое ты читаешь из InputBuffer.Size.
Так вот этот самый InputBuffer и есть ничто иное как "вспомогательный буфер", аккумулирующий принимаемый из гнезда вх.поток данных.


> Мне нужен был поток, который бы при чтении декрементировал
> position и уменьшал размер. Подобно Connection"у. Оных не
> нашёл - пришлось наследовать самому


Нормальное решение.
За образец класса, реализующего два независимых позиционных стрим-маркера (тек.позиция записи и тек.позиция чтения) можно было взять класс TDataBlock (sconnect.pas).


> Адрес или указатель на этот адрес ?


Данные указ.типа (pointer) предназначены для хранения адресов.

Следующие высказывания эквивалентны по смыслу:
Содержимое переменной (параметра) типа pointer
a) содержит адрес неких данных некоего типа.
b) указывает на некие данные некоего типа
с) ссылается на некие данные некоего типа


> data здесь воспринимается не как указатель на первый элемент
> массива (как в C), а как сам массив, адрес которого ещё
> нужно вычислить ?


Да, верно.

Для вычисления адреса переменной data в дан.случае как раз и применяется префикс @. Вычисленный таким образом адрес трактуется компилятором как данные указ.типа, что не противоречит типу форм.параметра, объявленного как pointer.


> Предположим, я передам data там, где требуется указатель
> на адрес (pointer)


Ты его попросту не передашь. Компилятор выдаст ошибку "несоответствие типов формального и фактического параметров", ибо формально ожидается адрес данных, а фактически передаются сами данные.


> компилятор возмёт первые 4 байта массива и интерпретирует
> их как адрес данных, с которыми он будет работать ?


Нет, не возьмет. См. выше. В том и прелесть Паскаля, что его строгость не допускает никаких неоднозначных трактовок, что сводит к минимуму ошибки, являющиеся следствием таких неоднозначностей (в Сях они сплошь и рядом).


> длина статического массива хранится в байтах перед первым
> элементом массива ?


Нет, не хранится.
Поскольку данные статические, компилятор имеет все основания распределить будущую память под них уже на этапе компиляции.
Подобное реализовано лишь для динамических данных, размер которых вычисляется лишь в ран-тайм и может быть изменен.


 
Cyrax ©   (2006-09-14 23:14) [90]

1. Насчёт Free. Что-то сразу не подумал и понаставил для своих классов Free вместо Destroy. Естественно, в этом случае будет вызываться Free базового класса (TMemoryStream.Free), который о моих Destroy"ях даже и не догадывается...

2. Очередь TQueue. Довольно тонкий вопрос совмещения очереди Queue (типа TQueue или TObjectQueue) и разделяемого потоками списка ThreadList (типа TThreadList), содержащего указатели на данные клиентов.
    Дело в том, что если взять очередь указателей (TQueue), то воле-неволей попытаешься направить их на те же участки памяти, куда указывают элементы списка ThreadList. Но в момент доступа к данным клиентов с помощью этой очереди никаких блокировок не происходит (как в случае доступа через TThreadList.LockList.Items...). Т.е. этот вариант отпадает из-за невозможности заблокировать ThreadList (доступ к клиентским данным осуществляется, минуя его)...
    Если же взять очередь объектов (TObjectQueue), то единственно эффективным вариантом будет хранить в этой очереди, например, идентификаторы (целое число) клиентов (сейчас я так и сделал), которые являются одним из полей структуры, содержащей клиентские данные.
    Минусом такой организации очереди является необходимость при каждом очередном доступе к какому-либо клиенту по полученному из очереди идентификатору искать соответствующие данные по списку ThreadList.
    Другой минус - необходимость синхронизации очереди ObjectQueue и списка ThreadList при каждом соединении/отсоединении клиента.
    Плюс очереди объектов - каждая операция доступа к клиентским данным происходит через список ThreadList, что влечёт за собой обязательную блокировку списка.

3. Требуется ограничить число одновременно подключенных клиентов (const ClientsMax). Подключение обрабатывается в OnConnect, т.е. ничего передать в использующую модуль программу не получится. Поле ListenQueue сервера (IdTCPServer) - как раз для этого. Допустим, я установлю его в 256. Что произойдёт, если попытается подключиться 257-й клиент ?  Полный игнор ?  Не вызовется даже OnConnect ?  Или возникнет исключение (если так, то где, в каком месте) ?  В любом случае мне нужно зафиксировать такую попытку соединения, чтобы сообщить при первой возможности использующей модуль программе.

4. В дочернем классе объявлен метод, одноимённый с методом родительского класса (ReadBuffer, WriteBuffer) без перегрузки. Как вызвать метод родительского класса из дочернего ?

5. Не совсем удобно получается с поиском или перебором клиентских данных с помощью цикла for. Дело в том, что в заголовке цикла указывается верхний предел, который получаем из ThreadList.LockList.Count. Но здесь происходит блокировка списка. Затем в теле цикла осуществляется доступ к клиентским данным (ThreadList.LockList.Items...). Каждая такая операция сопровождается очередной блокировкой. Сколько таких блокировок произойдёт внутри цикла - заранее неизвестно (придётся столько же раз разблокировывать). Единственный выход из ситуации - загнать в локальную переменную величину ThreadList.LockList.Count, разблокировать список (через finally), записать заголовок цикла с помощью этой локальной переменной, а в теле цикла каждую операцию доступа к списку ThreadList завершать (через finally) UnLock"ом.
При этом происходит загромождение кода этими try"ами и finally"ами (от 2 пар на 1 цикл for). Гораздо эффективнее было бы, например, если бы имелась возможность получать доступ к элементам списка неблокирующим способом (ну можно, конечно, дополнительно хранить указатель на список, получаемый через ThreadList.LockList.Items..., но это уже слишком). Тогда достаточно было бы заблокировать список (а точнее, объект ThreadList) перед циклом и разблокировать после него. А в заголовке и в теле цикла использовать неблокирующие операции доступа к списку.

6. Не совсем понятно поведение программы при попытке получения доступа к списку другим потоком (поток, который запер список, как я понял, может без проблем получить к этому списку доступ, даже если он его не разблокировал). Что в этот момент происходит - ожидание, когда список окажется разблокированным, или выбрасывается исключение ?  Или участок кода игнорируется ?
В коде у меня были ошибки подобного характера и не только, которые, к счастью, все исправлены. Намучался не хило, так что экспериментировать больше не хочется... :)

____________________________________________________________________
Сергей М. ©   (14.09.06 09:34) [89]
За образец класса, реализующего два независимых позиционных стрим-маркера (тек.позиция записи и тек.позиция чтения) можно было взять класс TDataBlock (sconnect.pas).

Да, можно и так. Но всё же оставлю прежний вариант с одним указателем.
(Всё равно придётся самому перемещать указатели)

Следующие высказывания эквивалентны по смыслу:
Содержимое переменной (параметра) типа pointer
a) содержит адрес неких данных некоего типа.
b) указывает на некие данные некоего типа
с) ссылается на некие данные некоего типа

Если в последнем пункте под словом "ссылается" понимается не ссылка на
данные, а указатель, то да, соглашусь.
Моё ИМХО:
В Object Pascal, как и в C, ссылки и указатели различаются следующим образом. По поведению в программе значением ссылки являются данные, а указателя - адрес, хотя на уровне реализации и те, и другие представлены адресами данных, на которые ссылаются/указывают.

См. выше. В том и прелесть Паскаля, что его строгость не допускает никаких неоднозначных трактовок, что сводит к минимуму ошибки, являющиеся следствием таких неоднозначностей (в Сях они сплошь и рядом).

Ну, в C компилятор тоже выдаст ошибку, если вместо указателя передать данные (имя массива там не относится к таким данным). А неоднозначностью передачу имени массива я не считаю, поскольку там нет таких случаев, где бы имя массива интерпретировывалось не как указатель на первый его элемент... :)

Кстати, понравилась такая запись нескольких действий в одну строку:

InputBuffer := get_client(Integer(id_queue.push(id_queue.pop))).InputBuffer;

(Сильно напоминает C++...)

____________________________________________________________________
Dmitrij_K   (12.09.06 22:35) [86]
В Classes.pas ищи TCustomMemoryStream.Read

Всё хорошо, только вот в режиме отладки в библиотечные функции не пускают... В release-варианте, наверное, скомпилен (Delphi)...
Да ещё по Ctrl в ReadBuffer пускают, а дальше - в Read (это который от TCustomMemory) - никак...


 
Сергей М. ©   (2006-09-15 09:07) [91]


> Cyrax ©   (14.09.06 23:14) [90]


1. Правильно сделал, что "понаставил .. Free".


> в этом случае будет вызываться Free базового класса (TMemoryStream.
> Free), который о моих Destroy"ях даже и не догадывается


Еще как догадывается.

2. TThreadList вполне подходит для организации очереди.
А если уж удобней использовать T[Object]Queue, придется организовать защиту обращений к очереди с пом. крит.секции (сделать класс TThread[Object]Queue по аналогии с TThreadList совсем не трудно)


> Что произойдёт, если попытается подключиться 257-й клиент
> ?


Клиент успешно подключится, но сервер втихомолку тут же сделает ему
disconnect, никаких событий и /или исключений сервер при этом не возбудит.


> 4. В дочернем классе объявлен метод, одноимённый с методом
> родительского класса (ReadBuffer, WriteBuffer) без перегрузки.
>  Как вызвать метод родительского класса из дочернего ?


К чему создавать себе трудности ?
Есть методы Read/Write, они виртуальные. Перекрой их в своем наследнике, тогда соотв.методы предка легко вызываются с пом. inherited.
Методы же ReadBuffer/WriteBuffer не виртуальные, и все что они делают - вызывают соответствующие вирт.методы Read/Write.


> 6. Не совсем понятно поведение программы при попытке получения
> доступа к списку другим потоком


Поток, захвативший крит.секцию, может смело манипулировать ресурсами (в твоем случае - списком), защищенными этой секцией, вплоть до освобождения секции.
Все прочие потоки, пытаясь захватить ту же секцию для доступа к тому же ресурсу, будут приостановлены до момента пока захвативший секцию поток не освободит ее.


 
Cyrax ©   (2006-09-18 21:34) [92]

Сергей М. ©   (15.09.06 09:07) [91]
> в этом случае будет вызываться Free базового класса (TMemoryStream.
> Free), который о моих Destroy"ях даже и не догадывается
Еще как догадывается.

Ну да...

2. Слепил свой класс TClientThreadQueue, унаследовав TQueue и TThreadList. Получил комбайн высшего класса. :)

3 Клиент успешно подключится, но сервер втихомолку тут же сделает ему
disconnect, никаких событий и /или исключений сервер при этом не возбудит.

Как тогда зафиксировать факт такой попытки ?

4. Я унаследовал класс TTCPServer от TIdTCPServer. Далее пытаюсь проинициализировать обработчики событий:
inherited OnExecute      := onexecute;
nherited OnConnect      := onconnect;
inherited OnDisconnect   := ondisconnect;
Почему после наследования приходится приписывать к ним inherited.
Без них - ошибка.

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

6. Как в Delphi перегрузить глобальную функцию ?

7. При организации приёма/передачи данных на сервере с помощью входных и выходных (для каждого клиента) буферов возникает "проблема" получения результата операции, поскольку сервер отправляет в буфер выходные данные, а сам занимается другими делами. А OnExecute"ы занимаются обработкой входных и выходных буферов. Так вот, смущает тот факт, что на сервере мы не получаем оперативной информации о выполнении операции отправки/приёма, а на клиенте (там уже наших входных/выходных буферов нет, OnExecute"ов нет) мы эту информацию получаем сразу по исключению при выполнении метода TIdTCPClient.Connection.ReadBuffer.
Хотелось бы, чтобы всё-таки и на сервере, и на клиенте это дело одинаково было. Поскольку в модуле мне приходится объявлять константу ConnectionError (в составе перечислимого типа TNetResult), которая будет формироваться только клиентом, тогда когда сервер тоже имеет дело с соединениями...

8. Отключаю сервер при подсоединённом клиенте. Для всех клиентов вызываются disconnect"ы. Тем не менее после вызова этих disconnect"ов генерируется исключение (именно из-за disconnected, 1-й параметр - true) на ReadFromStack (сейчас я эту ф-цию не использую, но вопрос стоит) в OnExecute, хотя в OnExecute вначале у меня стоит проверка на Connected.
Если OnDisconnect вызывается в том же потоке (т.е. одно вызывается после другого), что и OnExecute (что и должно быть), то как можно проскочить проверку на Connected вначале OnExecute ?

9. Не совсем понятен смысл свойства ListenQueue объекта класса TIdTCPServer (а именно "unresolved connections").

10. Задача такова. Нужно считать из стека TCP данные без блокировки. Если входных данных нет - не ждать пока они придут, вернуть 0. Если есть - вернуть их количество.
Так вот, ReadFromStack, если на входе нет данных, ждёт пока не придёт хотя бы 1 байт, после возвращает их количество. Можно задать timeout = 0, тогда сразу вернёт 0, если на входе нет данных.
Функция CurrentReadBuffer вызывает ReadFromStack, если Connected. Т.е. её поведение аналогично ReadFromStack. НО: вызывает она ReadFromStack с одним параметром - true. Т.е. 2-й параметр по ум. = -1 (ждать вечность, пока не придёт хотя бы 1 байт). Получается, если использовать функцию CurrentReadBuffer, то, если на входе нет ни байта, то будем ждать вечность. Как этого избежать, не используя ReadFromStack с нулевым вторым параметром.

11. Не могу понять, как можно получить данные по Pointer"у без приведения его к какому-нибудь типизированному указателю:
buffer^, где buffer типа Pointer...

12. Free можно вызвать даже через объект (котороый является указателем, т.к. объекты - это указатели), который = nil.
Парадокс...


 
Сергей М. ©   (2006-09-19 08:53) [93]


> Cyrax ©   (18.09.06 21:34) [92]


> Ну да...


Вот тебе и "ну да")


> Слепил свой класс TClientThreadQueue, унаследовав TQueue
> и TThreadList. Получил комбайн высшего класса


В Делфи у класса-наследник может быть только один класс-предок.
Думаю, тебя ждет шнобелевская премия, поскольку ты умудрился унаследовать аж два класса)
К тому же оба этих класса оперируют каждый своим отдельным списком)


> Как тогда зафиксировать факт такой попытки ?


А зачем ?


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


Потому что у тебя ошибка в декларации/реализации/использовании конструктора и деструктора "производного" класса (*)


> Почему после наследования приходится приписывать к ним inherited.


См. (*)


> Как в Delphi перегрузить глобальную функцию ?


Вот так:

function SomeFunction(SomeParams): SomeResultType; overload;
function SomeFunction(SomeOtherParams): SomeResultType; overload;


> 7.
> 8.


Ерунда какая-то ..
Иллюстрируй свою мысль в коде  ..


> 9.


Что конкретно не понятно ?


> Функция CurrentReadBuffer вызывает ReadFromStack, если Connected.
>  Т.е. её поведение аналогично ReadFromStack. НО: вызывает
> она ReadFromStack с одним параметром - true


см. параметр метода TIdTCPClient.Connect()


> как можно получить данные по Pointer"у без приведения его
> к какому-нибудь типизированному указателю


Никак.


> Free можно вызвать даже через объект (котороый является
> указателем, т.к. объекты - это указатели), который = nil.
> Парадокс...


Никакого парадокса.

Читай справку:

Every object inherits a Destroy method (called a destructor
) from TObject. To destroy an object, however, you should call the Free method (also inherited from TObject), because Free checks for a nil reference before calling Destroy


 
Cyrax ©   (2006-09-20 09:56) [94]

>Сергей М. ©   (19.09.06 08:53) [93]
>> Cyrax ©   (18.09.06 21:34) [92]
>> Ну да...
>Вот тебе и "ну да")

Я хочу сказать, что в моём классе не объявлен Free, поэтому, вызывается Free базового класса, который ну просто никак не обязан шерстить своих потомков в поисках Destroy...

>> Слепил свой класс TClientThreadQueue, унаследовав TQueue
>> и TThreadList. Получил комбайн высшего класса

Я провёл цептографическое наследование классов с генерацией fusion-объектов...
Так-что проблема отдельных списков решена...

> Как тогда зафиксировать факт такой попытки ?
А зачем ?

Например, для информирования сервером оператора...

> Почему, когда ты в производном классе определяешь конструктор
> и деструктор, при их вызове (а вернее, до и после, соответственно)
> автоматически не вызываются конструкторы и деструкторы базового
> класса ?
Потому что у тебя ошибка в декларации/реализации/использовании конструктора и деструктора "производного" класса (*)

Я так не думаю...

> Почему после наследования приходится приписывать к ним inherited.
Ну уж не может быть так, чтобы всё наследовалесь от TIdTCPServer, а
OnExecute"ы и т.п. - нет...

> 7.
> 8.
Такие вопросы кодом сложно.

> 9.
Что конкретно не понятно ?

Какие соединения относятся к неразрешённым.. %-|

> Функция CurrentReadBuffer вызывает ReadFromStack, если Connected.
>  Т.е. её поведение аналогично ReadFromStack. НО: вызывает
> она ReadFromStack с одним параметром - true
см. параметр метода TIdTCPClient.Connect()

Это не есть 2-й параметр ReadFromStack. И это только для initiate connection.
Мне же нужно для операций чтения/записи...

>> как можно получить данные по Pointer"у без приведения его
>> к какому-нибудь типизированному указателю
>Никак.

Фрагмент корректно работающего кода:
...
buffer: Pointer;
...
AThread.Connection.ReadBuffer(buffer^,data_len);
...

Речь идёт о безошибочности операции разыменования...

Dmitrij_K   (12.09.06 22:35) [86]
В Classes.pas ищи TCustomMemoryStream.Read

Всё хорошо, только вот в режиме отладки в библиотечные функции не пускают... В release-варианте, наверное, скомпилен (Delphi)...
Да ещё по Ctrl в ReadBuffer пускают, а дальше - в Read (это который от TCustomMemory) - никак...


 
Dmitrij_K   (2006-09-20 10:53) [95]


> Всё хорошо, только вот в режиме отладки в библиотечные функции
> не пускают..

Project-Options-Compiler- On Use Bebug DCUs


 
Сергей М. ©   (2006-09-20 11:05) [96]


> в моём классе не объявлен Free, поэтому, вызывается Free
> базового класса, который ну просто никак не обязан шерстить
> своих потомков в поисках Destroy


Обязан.
Потому что Destroy - виртуальный метод.


> Например, для информирования сервером оператора


Зачем серверу оператор ? Зачем оператору инф-ция об отверженном соединении ?


> Я так не думаю


Ну тогда продолжай в том же духе.


> Такие вопросы кодом сложно


Ты считаешь более простым объяснять тебе на пальцах неизвестно что и неизвестно почему происходящее в неизвестно каком коде ?


> Какие соединения относятся к неразрешённым


Те которые ждут акцептирования, т.е. потенциальные.


> Мне же нужно для операций чтения


Тогда см. св-во TIdTCPConnection.ReadTimeout


> Фрагмент корректно работающего кода:
> ...
> buffer: Pointer;
> ...
> AThread.Connection.ReadBuffer(buffer^,data_len);


Разыменование здесь нужно потому что переменная buffer объявлена именно как pointer, в то время как соотв.форм.параметр объявлен как нетипизированный и передаваемый по ссылке, а не по значению.

Конструкция buffer^ в этом случае означает предписание компилятору сгенерировать код, передающий фактическим параметром не адрес переменной buffer, а адрес, хранящийся в этой переменной.

Вот если бы ты объявил, к примеру,
buffer: array[...] of sometype
то тогда разыменование не потребовалось бы, потому что по ссылке будет передана сама переменная, в которую будет осуществляться чтрение, что собственно и требуется.


 
Сергей М. ©   (2006-09-20 14:08) [97]

По поводу Free ..

Если ты имеешь

TMyClass = class(...)
...
 destructor Destroy; override;
end;

TMyClass1 = class(TMyClass)
...
 destructor Destroy; override;
end;

TMyClass2 = class(TMyClass1)
...
 destructor Destroy; override;
end;

и создаешь объект класса TMyClass2

var MyObject: TMyClass;
MyObject := TMyClass2.Create(..);

то при вызове MyObject.Free (или непосредственно MyObject.Destroy, что несущественно в дан.случае) самым первым будет вызван метод TMyClass2.Destroy, поскольку этот метод перекрывает соотв.виртуальный метод предка, который точно так же перекрывает соотв.виртуальный метод своего предка, который... и так далее вплоть до TObject.Destroy, который собственно и объявлен как виртуальный метод, допускающий перекрытие (override) в своих потомках.


 
Cyrax ©   (2006-09-21 23:04) [98]

У меня механизм обработки входных данных следующий.
При инициализации клиента/сервера указывается процедура, которая будет вызываться, когда приходят данные. Вызов происходит в OnExecute соответствующего дочернего потока. При этом не допускается одновременных выполнений этой процедуры в нескольких потоках. Т.е. процедура должна полностью завершиться до начала следующего её вызова.
Имеем 2 варианта реализации вызова:
1. Делаем что-то типа lock"ов для чего-то...
2. Вызываем эту процедуру на выполнение в главный (первичный) поток с помощью synchronize(метод без парам). Но здесь возникает проблема: процедура у меня с параметрами. Как ето самое уделать ?

з.ыз. В случае 2 как раз и будет неявно организована очередь обработки запросов клиентов.


 
Сергей М. ©   (2006-09-22 08:17) [99]


> Вызов происходит в OnExecute соответствующего дочернего
> потока. При этом не допускается одновременных выполнений
> этой процедуры в нескольких потоках


Ну и нафиг тогда тебе Инди со всеми его наворотами ?
Индейский сервер изначально подразумевает его использование для параллельной обработки клиентских запросов.
Бзял бы обычный TServersocket или TTCPServer в режиме non-blocking - там события возбуждаются последовательно в одном-единственном потоке (например, в основном), и никакие заморочки с крит.секциями и прочей синхронизацией изобретать совершенно не нужно.


> synchronize(метод без парам). Но здесь возникает проблема:
>  процедура у меня с параметрами. Как ето самое уделать ?
>


Вот так:

TMyThread = class(TSomeThreadAncestor)
 ..
 FSomeParam: SomeType;
 ..
 procedure SomeSyncMethod;
 procedure SomeProc(SomeParam: SomeType);
end;

....

procedure TMyThread.SomeSyncMethod;
begin
  SomeProc(FSomeParam);
end;

...

FSomeParam := SomeValue;
Syncronize(SomeSyncMethod);


 
Cyrax ©   (2006-09-24 23:04) [100]

Сергей М. ©   (22.09.06 08:17) [99]
Ну и нафиг тогда тебе Инди со всеми его наворотами ?

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

11. Задача такова. Есть функция, которая принимает параметр типа PData.
Тип PData - какой-либо типизированный указатель, включая PChar.
При вызове функции в качестве фактического параметра передаётся PData(параметр_типа_Pointer). Но в случае с PChar генерируется статическая ошибка.
Как этого избежать ?  Почему PChar не приводится к Pointer ? Ведь это просто указатель на Char...
Дело в том, что среди возможных типов PData должен быть такой, чтобы доступ к элементам осуществлялся путём индексации (как в случае с PChar).

Обязан.
Потому что Destroy - виртуальный метод.

Тогда в своих деструкторах и конструкторах придётся самому вызывать деструкторы и конструкторы базового класса. Не очень то удобно...

Зачем серверу оператор ? Зачем оператору инф-ция об отверженном соединении ?

Допустим, сервер ведёт статистику, собирает и обрабатывает подобную (и не только) информацию. В любой момент можно быдет посмотреть, какие клиенты подключены, каким соединениям и когда было отказано и т.п.
Эта информация в любом случае не помешает...

>> Почему, когда ты в производном классе определяешь конструктор
>> и деструктор, при их вызове (а вернее, до и после, соответственно)
>> автоматически не вызываются конструкторы и деструкторы базового
>> класса ?
>Потому что у тебя ошибка в декларации/реализации/использовании
>конструктора и деструктора "производного" класса (*)

Я так не думаю...
>Ну тогда продолжай в том же духе.
А по моему, виртуальный метод не должен вызывать соответствующий метод базового класса...

Ты считаешь более простым объяснять тебе на пальцах неизвестно что и неизвестно почему происходящее в неизвестно каком коде ?

Дело в том, что для моделирования подобных ситуаций и представлении их в ярко выраженной форме потребуется потратить время на выдумывание такого кода. А в моей программе такие ситуации имеют место, но не в такой выраженной форме, чтобы только по коду можно было понять вопрос, да и части кода будут из разных мест программы + всё-равно потребуются письменные комментарии и разьяснения...

Те которые ждут акцептирования, т.е. потенциальные.

Почему слушающий поток не всегда может установить соединение и выделить клиенту отдельный поток, чтобы эти неразрешённые соединения накапливались...

4. Я унаследовал класс TTCPServer от TIdTCPServer. Далее пытаюсь проинициализировать обработчики событий:
inherited OnExecute      := onexecute;
nherited OnConnect      := onconnect;
inherited OnDisconnect   := ondisconnect;
Почему после наследования приходится приписывать к ним inherited.
Без них - ошибка.

Разыменование здесь нужно потому что переменная buffer объявлена именно как pointer, в то время как соотв.форм.параметр объявлен как нетипизированный и передаваемый по ссылке, а не по значению.

Вообще странно, что допускается разыменование нетипизированного указателя... В  C++ так делать нельзя...

12. Чем отличается тип Pointer от PVariant ?
13. И почему в сигнатуре методов пишут var имя_парам, а не var Vaiant. Т.е., фактически, пропускают тип параметра...


 
Сергей М. ©   (2006-09-25 08:13) [101]

Дискуссия перешла в русло абстрактной "болтологии" на тему Паскаля, к сетям не имеющей отношения.

Формулируй свои вопросы отдельно в порядке их возникновения, с иллюстрациями в коде, и задавай их в конф-ции "Общие" или "Начинающим".


 
Cyrax ©   (2006-10-09 23:14) [102]

Что-то я забросил ветку...
Всё-таки половина вопросов была по сетям.

1. Сейчас у меня такая ситуация. Клиент отсылает запросы серверу. 1 запрос - 1 прикладной пакет (10-30 байтов). Сервер поддерживает как SPX/IPX-протокол, так и TCP/IP. На стороне сервера, как только приходят данные (хотя бы 1 байт), вызывается функция, их обрабатывающая. Проверка появления входных данных на серверном сокете происходит в отдельном потоке в цикле OnExecute, т.е. практически непрерывно. В случае с TCP/IP наблюдается ситуация, когда эта функция получает блок данных, соответствующий нескольким запросам клиента (*). Запросы же клиент отсылает отдельно, друг за другом, с некоторыми промежутками. В случае с SPX/IPX функция обрабатывает входные данные отдельными прикладными пакетами, т.е. ситуации, когда функция вызывается после прихода на серверный сокет нескольких клиентских прикладных пакетов, не наблюдается... (для SPX/IPX вызывается другая функция, но выполняющая практически те же действия)
Конечно, такие ситуации в общем случае вполне могут быть. Но настораживает то, что проверка в OnExecute происходит практически непрерывно и появление на серверном сокете очередного прикладного пакета должно быть сразу же зафиксировано и вызвана соответствующая функция, не дожидаясь, пока придёт ещё один прикладной пакет...

з.ы. не объединяются ли прикладные пакеты в один IP-пакет (по "вине" ОС) на клиентской стороне (стороне отправителя), поскольку прикладной пакет намного меньше среднего размера IP-пакета ?
И какие задержки могут привести к таким результатам (*)

Рассматриваемые ситуации с TCP и IPX полностью идентичны за исключением протокола...

2. Какие проги можете посоветовать для слежки за передачей IP-пакетов в винде. Желательно небольшие, чтоб можно было закачать по dialup"у...


 
Ketmar ©   (2006-10-09 23:18) [103]

естественно, аккумулируется в буфере винсока.

Ethereal.


 
Cyrax ©   (2006-10-09 23:21) [104]

И как ету аккумуляцию придушить ?


 
Ketmar ©   (2006-10-09 23:32) [105]

а зачем? ну, положим, можно. но -- зачем? лучше код напиши правильно.


 
Cyrax ©   (2006-10-09 23:44) [106]

Ketmar ©   (09.10.06 23:32) [105]
а зачем? ну, положим, можно. но -- зачем? лучше код напиши правильно.

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


 
Ketmar ©   (2006-10-10 00:16) [107]

ну и "перепосылай". или сделай разборщик на простом автомате. а буфера -- не трогай. их не зря сделали. %-)


 
Cyrax ©   (2006-10-10 08:04) [108]

Ну, скажем, ковыряться в имплементе функции, обрабатывающей данные, не в моей компетенции. Я лишь вызываю её, когда приходят данные.
Функция работате правильно только тогда, когда вызывается только для одного очередного прикладного пакета...


 
Cyrax ©   (2006-10-10 08:07) [109]

И насчёт аккумуляции. До каких пор данные будут буферизоваться (до какого размера). И через какое время они начинают передаваться (если данных для буферизации больше не поступает)...


 
Сергей М. ©   (2006-10-10 08:49) [110]


> До каких пор данные будут буферизоваться (до какого размера)


Это определяется алгоритмом Нагеля.

см. SetSockOpt(TCP_NODELAY)


 
Cyrax ©   (2006-10-10 16:17) [111]

Не пашет:

const Id_SO_True: boolean = true;
     Id_SO_False: boolean = false;
begin
 Self.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_TCP_NODELAY, Char(@Id_SO_False), SizeOf(Id_SO_False));

Ошибка типа доступ по такому-то адресу...
Превым параметром ставил и Id_IPPROTO_TCP, и Id_IPPROTO_IP - то же самое...


 
Сергей М. ©   (2006-10-10 16:41) [112]


> по такому-то адресу


Вот по именно такому-то адресу и ищи ошибку.
см. Search -> Find Error ..

Надеюсь, вся эта катавасия у тебя происходит для гнезда-передатчика.


 
Cyrax ©   (2006-10-11 17:31) [113]

Надеюсь, вся эта катавасия у тебя происходит для гнезда-передатчика.

Да. Но этот же сокет передатчика является и сокетом приёмника - двусторонняя связь...

Вот по именно такому-то адресу и ищи ошибку.
см. Search -> Find Error ..

И что я должен высмотреть в этих регистрах и дампах...


 
Сергей М. ©   (2006-10-11 17:43) [114]


> Cyrax ©   (11.10.06 17:31) [113]



> этот же сокет передатчика является и сокетом приёмника


"Приемнику" алгоритм Нанеля по барабану - этот алгоритм актуален лишь для передающей стороны.


> что я должен высмотреть в этих регистрах и дампах


Справку читай, там все описано.


 
Cyrax ©   (2006-10-11 23:00) [115]

Справку читай, там все описано.

Уж не особо я полагаюсь на справку в Delphi...
Не особо ей доверяю...
Она не достаточно практична... Приходится рыться в инете.
(ошибаюсь ?)

Да и вообще, ассемблерным дебаггером в своё время активно пользовался.
В данном же случае меня интересует вопрос, касающийся ошибки...
Не думаю, что из Search -> Find Error что-то толковое выйдет. По-моему, достаточно вызова функции, которую я привёл выше, и парочку уточнений по моему модулю - и проблема будет решена (естественно, с помощью тех, кто работал с SetSockOpt)...


 
Сергей М. ©   (2006-10-12 08:28) [116]


> Приходится рыться в инете.
> (ошибаюсь ?)
>


В дан.случае ошибаешься.
Эта функциональность специфична именно для Delphi IDEб и где еще как не в "родной" справке к IDE искать ее описание ?


> Не думаю, что из Search -> Find Error что-то толковое выйдет


Если ошибка именно в твоем коде, Search -> Find Error покажет тебе строчку, при выполнении которой произошла эта ошибка.


 
Cyrax ©   (2006-10-15 19:15) [117]

При вводе адреса в моей программе, где произошла ошибка, ничего не происходит, окно "CPU" не открывается. Но по этому адресу мне делать нечего...
При вводе адреса, к которому произошло обращение (00000068), окно "СPU" открывается. Меня смущает этот адрес - 00000068...

const Id_SO_True: boolean = true;
       Id_SO_False: boolean = false;
begin
Self.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_TCP_NODELAY, PChar(@Id_SO_False), SizeOf(Id_SO_False));

Ну так кто-нибудь отключал буферизацию или нет !?
Если да, то как...


 
Ketmar ©   (2006-10-15 19:39) [118]

вот же прикопался к буферизации. чую, когда отключишь, будет пост типа "отключил. не помогло. что дальше?" %-)


 
Cyrax ©   (2006-10-15 20:09) [119]

Ketmar ©   (15.10.06 19:39) [118]
вот же прикопался к буферизации...

хочу дело до ума довести... потому-что надо...
Кстати вопрос с "освобождением" порта ещё не решён. После того, как отключу буферизацию, буду всех вас доставать этим портом, который на самом деле освобождается, но типа ведёт себя так, как будто не освобождается...
И вообще у меня много нерешённых проблем, в т.ч. с глюками дебагера и Qt-плагина в Eclipse, но этот вопрос нек вам...

чую, когда отключишь, будет пост типа "отключил. не помогло. что дальше?"

Если не поможет, буду отслеживать движение IP-пакетов и проводить всякие извращенские опыты...


 
Ketmar ©   (2006-10-15 21:26) [120]

>[119] Cyrax(c) 15-Oct-2006, 20:09
>Если не поможет, буду отслеживать движение IP-пакетов и
>проводить всякие извращенские опыты...
ага. вместо чтобы написать простейший автомат... или по ходу обсуждения задача уже поменялась? лень перечитывать.



Страницы: 1 2 3 4 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.11.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.81 MB
Время: 0.059 c
4-1151144061
Ketmar
2006-06-24 14:14
2006.11.12
scrollbar w COMBOBOX на диалоге -- нету %-(


15-1161983461
unknown
2006-10-28 01:11
2006.11.12
Clawfinger


15-1161962583
XProger
2006-10-27 19:23
2006.11.12
Перегрузка операторов в Delphi 10


9-1138389837
cava
2006-01-27 22:23
2006.11.12
картинки


1-1159532237
Ангела
2006-09-29 16:17
2006.11.12
Проблема с реестром.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский