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

Вниз

Можно ли заставить 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.036 c
3-31095
SSAlex
2003-06-17 01:34
2003.07.10
Как создать связь между таблицами Paradox?


7-31533
VadimProgrammer
2003-04-27 18:21
2003.07.10
Cd-Rw и Delphi


3-31147
Shaman
2003-06-18 17:31
2003.07.10
Описания к кодам ошибок MSSQL


1-31240
Andrey02
2003-06-28 19:39
2003.07.10
Thread поток - метод Synchronize. Качество программы.


1-31213
softmaster
2003-06-28 19:20
2003.07.10
экранные координаты





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский