Главная страница
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 м.
Делается это в дополнительном соединении, работающем по точно такой же схеме.



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

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

Наверх




Память: 0.58 MB
Время: 0.018 c
1-31260
mao
2003-06-29 18:09
2003.07.10
Richedit странно себя ведет...


14-31518
TCrash
2003-06-25 14:40
2003.07.10
проблема с кодеками


1-31337
Ivan Voronov
2003-06-27 12:44
2003.07.10
TShellListView и что-то подобное


14-31470
Den
2003-06-24 11:56
2003.07.10
1 запрос к 2 БД?


3-31079
Карелин Артем
2003-06-16 11:30
2003.07.10
Замедление работы компа после вставки большого числа записей.