Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.07.10;
Скачать: CL | DM;

Вниз

Можно ли заставить TIdTCPConnection сообщать о приходе данных?   Найти похожие ветки 

 
Zelius ©   (2003-04-29 17:28) [0]

На серверной стороне использую TidTcpServer, на клиенте TidTcpClient, хочу по одному каналау передавать данные как по инициативе клиента, так и сервера. Процедура оброботки TidTcpServer.OnExecute:

with aThread as TEPingConnThread do
begin
while NOT Terminated do
begin
HandleQueue; // отработать очередь данных на отсылку клиенту
if aThread.Connection.IOHandler.Readable(0) then HandleInput; // принять входящие данные
FEvent.WaitFor(500);
end;
end;

Мне не нравится интервал ожидания 500 мс, хочу от этого избавиться, но не знаю как это сделать с помощью Indy.


 
$hade ©   (2003-04-30 09:03) [1]

>Мне не нравится интервал ожидания 500 мс

А зачем ты тогда вставил FEvent.WaitFor(500)?
И кто такой TEPingConnThread,FEvent?


 
Zelius ©   (2003-04-30 13:09) [2]

Я его вставил, что бы этот поток не загружал процессор постоянным исполнением.
TEPingConnThread - это наследник TidPeerThread.


 
Reindeer Moss Eater   (2003-04-30 14:03) [3]

Никакого "постоянного выполнения" и так не будет.
OnExecute генерится только когда, когда есть что обрабатывать


 
$hade ©   (2003-04-30 14:06) [4]

а с чего он его грузить будет??
делай в первой строке OnExecute
readbuffer(b,sizeof(b)); - тут будет сидеть до тех пор пока не получит sizeof(b) байт от клиента или до TimeOut"а...
handleInput;

>TEPingConnThread - это наследник TidPeerThread
и что он делает у тебя?

Приведи побольше кода...понятней будет что ты хочеь сделать...


 
$hade ©   (2003-04-30 14:11) [5]

2Reindeer Moss Eater
на самом деле оно генерится не только когда есть что обрабатывать...
например когда у КЛИЕНТА ты вызываешь Read(...
когда клиент только что подключился - сразу же после обработки
OnConnect...и не факт что в этот момент есть что читать ОТ клиента...


 
Zelius ©   (2003-04-30 14:54) [6]

$hade © (30.04.03 14:06)
Дело в том, что я не могу блокировать поток отвечающий за прием данных, так как через него же хочу отправлять данные в произвольный момент, то есть на сервере произошло событие и мне надо об этом уведомить клиента, это может произойти в тот момент, когда поток будет висеть и ждать входящих данных.
А работаю я с потомком TidPeerThread для удобства, так как храню в нем данные необходимые для работы с каждым соединением.


 
Zelius ©   (2003-04-30 14:55) [7]


> Reindeer Moss Eater (30.04.03 14:03)
> Никакого "постоянного выполнения" и так не будет.
> OnExecute генерится только когда, когда есть что обрабатывать

Вы не правы, рекомендую посмотреть исходники Indy


 
$hade ©   (2003-04-30 15:22) [8]

блин! а что тебе мешает сделать так:
var // глобальные переменные
Th:IdPeerThread;
...

OnConnect(AThread:TIdPeerThread);
begin
Th:=AThread;
end;

OnExecute(AThread...
begin
AThred.connectiom.read... то есть тут происходит ТОЛЬКО чтение от клиента....
end;

и все.... далее в ЛЮБОМ месте (когда тебе надо отправить клиенту данные)
Th.Connection.writebuffer например...

Не согласен??

ps:естественно тут только общее описание...конкретно - для одного клиента...а для нескольких клиентов - посложнее будет...там много нюансов...
Я делал реальный проект - оно работает...
Ежели что - пиши на мыло...



 
$hade ©   (2003-04-30 15:25) [9]

есть такая штука - TThreadList..подумай над этим на досуге...;-)


 
Zelius ©   (2003-04-30 15:33) [10]


> $hade © (30.04.03 15:22)

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


 
Reindeer Moss Eater   (2003-04-30 15:41) [11]

на самом деле оно генерится не только когда есть что обрабатывать...
например когда у КЛИЕНТА ты вызываешь Read(...
когда клиент только что подключился - сразу же после обработки
OnConnect...и не факт что в этот момент есть что читать ОТ клиента...


Про ЧТЕНИЕ от клиента я не упоминал.

OnExecute генерится только когда, когда есть что обрабатывать

И отдавать тики процессора другим нитям в этом обработчике нет никакой необходимости. Это то что я хотел сказать.



 
Reindeer Moss Eater   (2003-04-30 15:48) [12]

Исходный вопрос:
Можно ли заставить TIdTCPConnection сообщать о приходе данных?
Ответ:
Заставлять не надо. Будет сгенерено событие OnExecute, которое и сигнализирует, что данные есть.


 
Reindeer Moss Eater   (2003-04-30 15:49) [13]

Или что пора вызывать синхроныый метод чтения данных


 
Zelius ©   (2003-04-30 15:57) [14]


> Reindeer Moss Eater (30.04.03 15:48)

Насколько я понял - OnExecute генерируется при установлении соединения, а не при приходе данных.


 
Reindeer Moss Eater   (2003-04-30 15:59) [15]

А OnConnect когда по твоему генериться?


 
Reindeer Moss Eater   (2003-04-30 16:06) [16]

А работаю я с потомком TidPeerThread для удобства, так как храню в нем данные необходимые для работы с каждым соединением.

Излишество это.
Есть TidPeerThread.Data в котором можно хранить ссылку на любые свои данные.


 
Zelius ©   (2003-04-30 16:14) [17]


> Reindeer Moss Eater (30.04.03 15:59)
> А OnConnect когда по твоему генериться?

Из DoConnect, который в свою очередь из BeforeRun.
Я посмотрел исходники - OnExecute вызывается не при появлении данных, а постоянно, пока соединение не закрыто и когда OnExecute возвращает управление! Что бы дождаться данных все равно надо вызывать ф-ию чтения и блокировать поток.


 
Zelius ©   (2003-04-30 16:16) [18]


> Reindeer Moss Eater (30.04.03 16:06)
> А работаю я с потомком TidPeerThread для удобства, так как
> храню в нем данные необходимые для работы с каждым соединением.
>
> Излишество это.
> Есть TidPeerThread.Data в котором можно хранить ссылку на
> любые свои данные.

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


 
Reindeer Moss Eater   (2003-04-30 16:23) [19]

Я посмотрел исходники - OnExecute вызывается не при появлении данных, а постоянно, пока соединение не закрыто и когда OnExecute возвращает управление! Что бы дождаться данных все равно надо вызывать ф-ию чтения и блокировать поток.

Reindeer Moss Eater (30.04.03 15:49)
Или что пора вызывать синхроныый метод чтения данных


Объясни тупому: блокировать-то зачем???


 
Reindeer Moss Eater   (2003-04-30 16:25) [20]

В OnExecute надо либо читать, либо писать. Зачем блокировать нитку PeerThread????


 
Zelius ©   (2003-04-30 16:40) [21]


> Reindeer Moss Eater (30.04.03 16:23)

Именно вызов синхронного метода чтения (а в инди других нет) и приводит к блокированию потока! Чего я и хочу избежать! Я не специально блокирую поток, а наоборот пытаюсь этого избежать :)


 
$hade ©   (2003-04-30 16:50) [22]

>Ты хочешь сказать, что можно одновременно из разных потоков по одному сокету принимать и посылать данные?

Почему из разных то?? это один и тот же поток....
создавать Th не надо...просто присваеваешь....

Вощщем примерно так это выглядит у меня...

procedure TSrvCore.TCPSrvConnect(AThread: TIdPeerThread);
var
NewClient: PClient;
begin
try
with ActiveClients.LockList do
begin
GetMem(NewClient, SizeOf(TClient));
NewClient.DNS := AThread.Connection.Socket.Binding.PeerIP + ":"
+ IntToStr(AThread.Connection.Socket.Binding.PeerPort);
NewClient.UserName := "Guest";
NewClient.WorkDir := "";
NewClient.ConnecttionID := ConnID;
NewClient.Autorized := false;
NewClient.AutorizeAttempt := 0;
NewClient.SoftwareVersion := 0;
NewClient.ConnectionTime := now;
NewClient.WorkState := 1;
NewClient.RecivedFiles := 0;
NewClient.RecivedBytes := 0;
NewClient.SendFiles := 0;
NewClient.SendBytes := 0;
NewClient.UserUID := random($FFFFF);
NewClient.Thread := AThread;
AThread.Data := TObject(NewClient);
Add(NewClient);
AT := Count;
end;
finally
ActiveClients.UnlockList;
end;

AThread.Connection.ReadTimeout := SrvSettings.Timeout;
AThread.Connection.Intercept:=CryptIntrecept;
AThread.Connection.OnWork := OnWork;
UpdateLV(usAddUser, NewClient);
end;
..............
ActiveClients:TThreadList; - лист потоков активных соединений...:-)
NewClient:PClient - указатель на структуру TClient - просто рекорд с данными о клиенте...

AThread.Data := TObject(NewClient); - после этого из любго события (execute,disconnect) я могу сделать
Cli:=PClient(AThread.Data) и в cli у меня будет вся инфа о подключенном клиенте...

NewClient.Thread := AThread; - с точностью до наоборот! т.е. из
любого места программы выбираем из ActiveClients (обычный TList,список только заточеный под многопоточность) item - и это будет ссылка на NewClient а там соответственно на AThread...
Например: Отправляем данные всем клиентам
with ActiveClients.LockList do
try
for i:=0 to Count-1 do
begin
Cli:=PClient(Items[i]);
TIdPeerThread(.cli.thread).Connection.Write("FuckOff");
TIdPeerThread(.cli.thread).Connection.Disconnect;
end;
finally
ActiveClients.UnLockList;
end;

Сильно запутанно...сорри...торопился...:-)



 
Reindeer Moss Eater   (2003-04-30 16:50) [23]

... и приводит к блокированию потока! Чего я и хочу избежать!
И что тебе это даст?


 
Reindeer Moss Eater   (2003-04-30 16:59) [24]

Дело конечно хозяйское, но TCP сервера работают примерно по такой схеме:
1. Дождаться запроса услуги от клиента
2. Выполнить запрос клиента, и отправить ему результат
3. Перейти к пункту 1.


 
$hade ©   (2003-04-30 17:03) [25]

2Reindeer Moss Eater
вполне согласен,но все же иногда надо что либо послать клиенту без его запроса...к примеру сообщение от админа сервера....в то время когда клиент заливает 50Mb файл на сервер...:-)


 
Zelius ©   (2003-04-30 17:04) [26]


> $hade © (30.04.03 16:50)

Я все понял кроме одного - можно ли параллельно с одного и того же сокета посылать и принимать данные, причем из разных потоков??? К сожалени, никак не могу найти статью на эту тему! Придется похоже руками пробовать...
По поводу кода, вместо ActiveClients я пользуюсь TcpServer.ThreadList, а вместо TClient я храню как раз данные в TMyidPeerThread, что вобщем одно и тоже.


 
Zelius ©   (2003-04-30 17:08) [27]


> Reindeer Moss Eater (30.04.03 16:59)

А иногда им еще надо передавать произвольные данные! Например аська! Сервер не только получает сообщения от клиента, но и передает их ему, когда те появляются!


 
$hade ©   (2003-04-30 17:18) [28]

>можно ли параллельно с одного и того же сокета посылать и принимать данные, причем из разных потоков???

а зачем?? зачем из разных то?? ты сохраняешь указатель на поток...и можеш обращаться к ЭТОМУ ЖЕ ПОТОКУ из любого места через указатель...


 
Zelius ©   (2003-04-30 17:34) [29]


> $hade © (30.04.03 17:18)

Конечно могу, но это не значит что посылка данных будет выполнена в контексте этого потока. В контексте потока код будет выполнен только тогда, когда он будет вызван из обработчика OnExecute. Или я что-то не понимаю...


 
Bug   (2003-04-30 17:36) [30]

$hade © (30.04.03 17:18)
>>а зачем?? зачем из разных то?? ты сохраняешь указатель на
>>поток...и можеш обращаться к ЭТОМУ ЖЕ ПОТОКУ из любого места
>>через указатель...
ты уверен?


 
$hade ©   (2003-04-30 17:46) [31]

2Bug
а ты нет? объясни...:-)

p:pointer;
AThread:TIdPeerThread;

p:=TObject(AThread);
...
TIdPeerThread(p).Connection.write <-> AThread.Connection.write

Это разные потоки??




 
Zelius ©   (2003-04-30 17:51) [32]


> $hade © (30.04.03 17:46)
> 2Bug
> а ты нет? объясни...:-)
>
> p:pointer;
> AThread:TIdPeerThread;
>
> p:=TObject(AThread);
> ...
> TIdPeerThread(p).Connection.write <-> AThread.Connection.write
>
> Это разные потоки??

Это разные потоки.


 
Zelius ©   (2003-04-30 17:53) [33]


> $hade © (30.04.03 17:46)

Сорри, поторопился! Нет, конечно это один и тот же объект, но посылая данные так как ты указал, ты посылаешь их в контексте скорее всего главного потока!


 
$hade ©   (2003-04-30 17:54) [34]

С чего бы это??


 
Zelius ©   (2003-04-30 18:00) [35]


> $hade © (30.04.03 17:54)

Потому что для того что бы воспользоваться контекстом потока TidPeerThread необходимо вставлять код в OnExecute. Ты проверь! Поставь бряк внутри OnExecute, посмотри в View \ Debug Windows \ Threads ID потока, а потом поставь бряк на твою отсылку данных и повтори тоже самое. Мне кажется, что это буду разные потоки.


 
$hade ©   (2003-04-30 18:14) [36]

$hade © (30.04.03 17:54)
С чего бы это??

Это относилось к
>Это разные потоки.

Просто мы вместе пишем...:-)

А по поводу
>Zelius © (30.04.03 18:00)
...да...возможно это разные потоки...то есть вызов write во втором случае идет из основного потока...

Это работает...правильно работает...тока пока я не могу объяснить...:-)))
(за 12 часов сидения за компом уже плохо соображаю...:-((...
часа через 2 вылезу...пообчаемся на эту тему дальше...пошел пиво пить....


 
Zelius ©   (2003-04-30 19:11) [37]


> $hade © (30.04.03 18:14)

Конечно это будет работать, только вот многопоточности не будет, будут чувствоваться тормоза при больших пересылках ( а если еще и через интернет, то и подавно), и потом, есть шанс, что связь оборвется в момент когда ты захочешь что-нибудь послать, в этом случае есть шанс получить ошибку что-то типа Access Violation.

Однако вопрос открыт!
Что-то мне не очень нравится Инди :( Вроде все идет нормально, а потом мелкая пакасть с ее стороны губит самые хорошие идеи! :( Останавливает только то, что не хочется тратить время на реализацию интернет протоколов...


 
Reindeer Moss Eater   (2003-04-30 20:11) [38]

Zelius © (30.04.03 17:08)

> Reindeer Moss Eater (30.04.03 16:59)

А иногда им еще надо передавать произвольные данные! Например аська! Сервер не только получает сообщения от клиента, но и передает их ему, когда те появляются!

Я тебе про сервер, а ты мне про клиента не рассказываешь.


 
Reindeer Moss Eater   (2003-04-30 20:15) [39]

Я все понял кроме одного - можно ли параллельно с одного и того же сокета посылать и принимать данные, причем из разных потоков??? К сожалени, никак не могу найти статью на эту тему! Придется похоже руками пробовать...
По поводу кода, вместо ActiveClients я пользуюсь TcpServer.ThreadList, а вместо TClient я храню как раз данные в TMyidPeerThread, что вобщем одно и тоже.


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


 
Reindeer Moss Eater   (2003-04-30 20:20) [40]

$hade © (30.04.03 17:03)
2Reindeer Moss Eater
вполне согласен,но все же иногда надо что либо послать клиенту без его запроса...к примеру сообщение от админа сервера....в то время когда клиент заливает 50Mb файл на сервер...:-)


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


 
Инди   (2003-04-30 20:45) [41]

Удалено модератором
Примечание: Не по делу можно в "Потрепаться"


 
$hade ©   (2003-05-01 11:38) [42]

2Reindeer Moss Eater (30.04.03 20:20)
>Делается это в дополнительном соединении, работающем по точно такой же схеме.

ну давай ща сделаем 25 подключений на каждого клиента...:-)

2Zelius © (30.04.03 19:11)

Конечно это будет работать, только вот многопоточности не будет, будут чувствоваться тормоза при больших пересылках ( а если еще и через интернет, то и подавно)

И почему же через интернет тормоз будет чуствоваться??? Попробуй отослать от сервера клиенту файл в 1 Mb по модему...выполнение Connection.WriteBuffer закончится намного быстрей чем данные примет клиент....()

, и потом, есть шанс, что связь оборвется в момент когда ты захочешь что-нибудь послать, в этом случае есть шанс получить ошибку что-то типа Access Violation.

скорее это будет "Socket Error #..."
и не ошибка а исключение...:-)
в обработчике OnDisconnect удаляешь из ActiveClients (в моем случае) указатель и все...
Поток уничтожается только после обработки OnDisconnect...


 
$hade ©   (2003-05-01 12:02) [43]

кста....посмотри Demos"ы для Indy (можешь скачать на www.nevrona/indy)
там есть пример чата(клиент/сервер)...как раз там все и сделано....


 
$hade ©   (2003-05-01 12:05) [44]

т.е. www.nevrona.com/indy


 
Zelius ©   (2003-05-02 19:54) [45]


> Reindeer Moss Eater (30.04.03 20:11)

И я тебе про сервер, или ты считаешь, что аськин сервер не отправляет сообщения?

> Reindeer Moss Eater (30.04.03 20:20)

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


 
Zelius ©   (2003-05-02 19:57) [46]


> И почему же через интернет тормоз будет чуствоваться???
> Попробуй отослать от сервера клиенту файл в 1 Mb по модему...выполнение
> Connection.WriteBuffer закончится намного быстрей чем данные
> примет клиент....()

а теперь умножь 1 мб на 10 клиентов!

> кста....посмотри Demos"ы для Indy (можешь скачать на www.nevrona/indy)
> там есть пример чата(клиент/сервер)...как раз там все и
> сделано....

Да, действительно там так и сделано... Хотя это странно... Вобщем, после праздников я попробую такую схему, но немешало бы теорией подкрепиться!


 
$hade ©   (2003-05-02 21:06) [47]

>Да, действительно там так и сделано... Хотя это странно...

Я тоже вначале сомневался...а сейчас - 5-25 клиентов цепляются к серваку(больше просто не надо)...и никаких проблем нет...и тормозов не замечаю...

>Вобщем, после праздников я попробую такую схему, но немешало бы теорией подкрепиться!

А как бы я хотел найти теорию...но нет у меня 100 евро которые просят авторы за месяц чтения какой то их онлайн книги...:-((

А по поводу "че та мне не нравятся эти Indy" и по поводу их глючности...да - есть конечно - но в основном - ты просто не умеешь их готовить....:-))


 
Reindeer Moss Eater   (2003-05-03 10:42) [48]

И я тебе про сервер, или ты считаешь, что аськин сервер не отправляет сообщения?

Уверен, что он делает это по своей инициативе, а не по запросу клиента?


 
Zelius ©   (2003-05-03 20:02) [49]


> Reindeer Moss Eater (03.05.03 10:42)

Нет.


 
Zelius ©   (2003-05-03 20:05) [50]


> А по поводу "че та мне не нравятся эти Indy" и по поводу
> их глючности...да - есть конечно - но в основном - ты просто
> не умеешь их готовить....:-))

А ты пробовал сделать на Инди скачку файла по HTTP в несколько потоков? Если когда-нибудь попробуешь - тебя ждут сюрпризы :)


 
Инди   (2003-05-03 23:29) [51]

ой-ей-ей! А давай я на тебе одном чего-нибудь в несколько потоков сделаю! В каждом потоке своя Инди должна быть! Вот.


 
Reindeer Moss Eater   (2003-05-04 11:14) [52]

Zelius ©
Представь картину:
Клиент начал качать файл с сервера. Сервер бьет файл на блоки и отдает клиенту. При этом сервер хочет отставить за собой право слать клиенту в ЛЮБОЙ момент времени сообщения (используя то же самое соединение). Что отсюда следует?
То, что КАЖДЫЙ блок пересылаемого файла сервер вынужден снабжать заголовком и маркером конца что бы клиент понял что же это такое он прочитал.
И чем это лучше отдельного соединения?


 
Zelius ©   (2003-05-04 14:01) [53]


> Reindeer Moss Eater (04.05.03 11:14)

Для этого варианта да, лучше отдельное соединение. А вообще, как раз для это и существует в сокетах OOB.


 
$hade ©   (2003-05-05 06:23) [54]

Reindeer Moss Eater (04.05.03 11:14)
Zelius ©
Представь картину:
Клиент начал качать файл с сервера. Сервер бьет файл на блоки и отдает клиенту. При этом сервер хочет отставить за собой право слать клиенту в ЛЮБОЙ момент времени сообщения (используя то же самое соединение). Что отсюда следует?
То, что КАЖДЫЙ блок пересылаемого файла сервер вынужден снабжать заголовком и маркером конца что бы клиент понял что же это такое он прочитал.
И чем это лучше отдельного соединения?

А чем хуже?? Вполне хватит заголовка в 5 байт...
[команда][размер данных][собсно данные]

Та же ICQ по такому протоколу и работает(только заголовок посложней...)


 
Reindeer Moss Eater   (2003-05-05 09:03) [55]

А чем хуже?? Вполне хватит заголовка в 5 байт...

Да ничем, кроме того, что этот заголовок надо приклеивать ко всем блокам, пересылаемым по сети. Получаем:
1. Бесполезное увеличение трафика
2. Усложнение своего протокола


 
Reindeer Moss Eater   (2003-05-05 09:04) [56]

И чем это лучше отдельного соединения?


 
$hade ©   (2003-05-05 11:22) [57]

Получаем:
1. Бесполезное увеличение трафика
не так уж и на много увеличение...(если павильно выбрать размер блока...)
ну и насчет бесполезности я бы тоже поспорил....
2. Усложнение своего протокола
согласен...есть такое...но опять же если правильно подойти к этому - не так уж это и усложнится....
зато в эти 5б ты можешь засунуть столько команд....

И чем это лучше отдельного соединения?

а ты не думал что есть всякие прокси,фаирволы и т.д.??
и открывать по 2 порта не всегда возможно...

зы: приведи ты пример проги работающей по 2 соединениям...по твоему алгоритму...


 
Reindeer Moss Eater   (2003-05-05 11:28) [58]

а ты не думал что есть всякие прокси,фаирволы и т.д.??
и открывать по 2 порта не всегда возможно...

Это больше относится к динамическим номерам портов, что автору не надо на самом деле

зы: приведи ты пример проги работающей по 2 соединениям...по твоему алгоритму...
Любой ftp клиент, Оракл в dedicated mode, ....


 
Zelius ©   (2003-05-05 15:35) [59]

Имхо, если можно обойтись одним соединением, то и надо им обходиться.

Спасибо $hade, надоумил, как можно работать с Индей.


 
Reindeer Moss Eater   (2003-05-05 16:58) [60]

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


 
$hade ©   (2003-05-06 06:02) [61]

Ну наконец то пришли к какому то выводу...:-) А то развели тут :-)



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

Текущий архив: 2003.07.10;
Скачать: CL | DM;

Наверх




Память: 0.64 MB
Время: 0.02 c
14-31514
picaroon
2003-06-25 10:01
2003.07.10
Помогите кто чем может с кодом


14-31447
anbezr
2003-06-23 18:43
2003.07.10
Определить, уничтожен ли объект


1-31348
Vint_XXX
2003-06-27 10:29
2003.07.10
ListView


8-31365
[Baradoo]
2003-03-18 22:43
2003.07.10
Создание проги-синтезатора! (срочно надо плиззз)


3-31106
victor_ch
2003-06-13 10:17
2003.07.10
Подключение к MSsql серверу