Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TIdTCPServer + несколько клиентов. [D7]


Страницы:   1 2 3

Gym ©   (2004-03-07 16:31:00) 

Здравствуйте уважаемые мастера.
Подскажите, пожалуйста, как в TIdTCPServer узнать ip и порт, с которого подключился клиент, количество подключённых клиентов. Как отослать каждому клиенту, допустим, текстовую строку.
Спасибо.


Verg   (2004-03-12 09:32:00) [21]

Что-то меня сомнения берут.
Насчет new(MyData).

Data : TObject

И когда клиент "сматывает удочки", не уничтожается ли Data
Таким образом - Data.Free ???

Есть мненние, что MyData должен быть классом, а не произвольной структурой данных.


Reindeer Moss Eater   (2004-03-12 08:49:00) [22]

а где её лучше освободить?

Когда клиент сматывает удочки


Fay   (2004-03-12 07:35:00) [23]

New + F1


Gym   (2004-03-12 04:43:00) [24]

to Reindeer Moss Eater

Огромное спасибо за потраченное на меня время.
Торжественно обещаю в ближайшее время засесть за книжки и
разобраться во всех этих обьектах, записях и полях.
А пока ещё один маленький вопрос.
Тут мы выделили память из кучи
New(MyData);
а где её лучше освободить?


Reindeer Moss Eater   (2004-03-11 22:04:00) [25]

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
var
Name   : string;
Pass   : string;
MyData : PMyData;
begin
Name:=AThread.Connection.ReadLn;
AThread.Connection.WriteLn('GET PASS');
Pass:=AThread.Connection.ReadLn;
AThread.Connection.WriteLn('OK');
New(MyData);
ATHread.Data:=TObject(MyData);
MyData^.Name:=Name;
MyData^.Pass:=Pass;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var i : integer;
begin
//LockList - функция. Возвращает TList. Каждый элемент в котором - экземпляр TidPeerThread
with idTCPServer1.Threads.LockList do
 try
  for i:=0 to Pred(Count) do
   Memo1.Lines.Add(PMyData(TIdPeerThread(Items[i]).Data)^.Name);
 finally
  //На каждый LockList должен быть свой UnlockList потому что каждый LockList использует критические секции
  idTCPServer1.Threads.UnlockList;
 end;
end;


Gym   (2004-03-11 20:25:00) [26]

to Reindeer Moss Eater

Вообщем попробовал сделать всё заново.
Привожу упрощённый текст моей программы.
Если в выделенной сторке оставить всё как есть то выскакивает ошибка:
[Error] ServUnit.pas(60): Incompatible types: 'TObject' and 'PMyData'
Если записать так:
  ATHread.Data:=@MyData;
То всё проходит нормально, но когда жмёшь на Button1 то получаешь ошибку. Access violation at address ... in module SERV.EXE. Write of address ... .

unit ServUnit;
interface
uses
 ...

type
 PMyData = ^RMyData;
 RMyData = record
   Name : string;
   Pass : string;
 end;

 TForm1 = class(TForm)
   Memo1: TMemo;
   Panel1: TPanel;
   IdTCPServer1: TIdTCPServer;
   IdAntiFreeze1: TIdAntiFreeze;
   Button1: TButton;
   Button2: TButton;
   Button3: TButton;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
   procedure IdTCPServer1Connect(AThread: TIdPeerThread);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 MyData : PMyData;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 idTCPServer1.Active:=True;
end;

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
var
 Name : string;
 Pass : string;
begin
 Name:=AThread.Connection.ReadLn;
 Memo1.Lines.Add(Name);
 AThread.Connection.WriteLn('GET PASS');
 Pass:=AThread.Connection.ReadLn;
 Memo1.Lines.Add(Pass);
 AThread.Connection.WriteLn('OK');
 New(MyData);
  ATHread.Data:=MyData;
 PMyData(AThread.Data)^.Name:=Name;
 PMyData(AThread.Data)^.Pass:=Pass;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 i : integer;
begin
 for i:=0 to idTCPServer1.Threads.LockList.Count-1 do
   begin
     Memo1.Lines.Add(PMyData(idTCPServer1.Threads.LockList.Items[i])^.Name);
   end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 idTCPServer1.Active:=False;
end;

end.


Gym   (2004-03-11 18:05:00) [27]

to Reindeer Moss Eater

Похоже так не получиться потому, что оператор
AThread.Data := @MyRec;
Записывает в переменную Data один и тот же адрес в памяти для
всех потоков. И если вставить этот оператор в обработчик
onConnect то каждый раз в переменную по адресу Data^ будут
записаны данные последнего потока, поверх тех что уже были.

Может чтоб реализовать хранение данных о конекте вместе с потоком
имеет смысл породить потомка от класса TIdPeerThread и добавить у него нужные поля?
Или нужен потомок от класса TIdTCPServer?

а потом я провёл экспиремент. Вывел ThreadID для всех потоков вот так:

   try
     for i:= 0 to Pred(Count) do
       begin
         mmLog.Lines.Add(IntToStr(
           PThread(TCPServer.Threads.LockList.Items[i])^.ThreadID));
        end;
 finally
   TCPServer.Threads.UnlockList;
 end;

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

for i:=0 to AllConection-1 do mmLog.Lines.Add(IntToStr(Aka[i].Thread.ThreadID));

перед этим в  обработчике OnConnect написал
  Aka[i].Thread:=AThread;
тут всё нормально ThreadID разные, причём ни один не совпадает с
выведенными первым способом.

Одна надежда на тебя. Подскажи пожалуйста что тут не так?


Reindeer Moss Eater   (2004-03-11 17:31:00) [28]

А кто за тебябудет создавать отдельные экземпляры структур на каждого клиента Пушкин что ли?

var
MyData : PMyRecord;

New(MyData);
AThread.Data := MyData;


Gym   (2004-03-11 17:26:00) [29]

Похоже так не получиться потому, что оператор
AThread.Data := @MyRec;
Записывает в переменную Data один и тот же адрес в памяти для
всех потоков. И если вставить этот оператор в обработчик
onConnect то каждый раз в переменную по адресу Data^ будут
записаны данные последнего потока, поверх тех что уже были.

Может чтоб реализовать хранение данных о конекте вместе с потоком
имеет смысл породить потомка от класса TIdPeerThread и добавить у него нужные поля? Или нужен потомок от класса TIdTCPServer?


Reindeer Moss Eater   (2004-03-11 15:44:00) [30]

with IdTCPServer1.Threads.LockList do
  try
   for i:= 0 to Pred(Count) do
    begin
     mmLog.Lines.Add(PMyRecord(TidPeerThread(Items[i]).Data)^.MySomeRecordField);
    end;
  finally
   IdTCPServer1.Threads.UnlockList;
  end;


Gym   (2004-03-11 15:33:00) [31]

to Reindeer Moss Eater

Да я уж понял что шутка. Правда сначала долго ломал голову, над тем, что ты имеешь в виду. :)))

Теперь о деле. С тем как в Data засунуть свою запись я вроде разобрался. Теперь как её оттуда вытащить.

ShowMessage('Поле MyName в записи TMyRecord имеет значение:' + PMyRecord(AThread.Data)^.MyName);

это подходит если я хочу обратиться из той же процедуры в которой
вводил данные например из procedure TfmServer.TCPServerConnect(AThread: TIdPeerThread);

А если мне нужно читать данные допустим по нажатию кнопки?
Я тут попробовал кое-что, но видно не правильно. Посмотри пожалуйста что не так.

type
 PThread = ^TIdPeerThread;
 PData = ^RDAta;
 ...

var
 CliData      : RData;
 ...

procedure TfmServer.TCPServerConnect(AThread: TIdPeerThread);
begin
 AThread.Data:=@CliData;
 PData(AThread.Data)^.Name:=('Name'+IntToStr(AllConection));
 ...
 AllConection:=AllConection+1;
end;

procedure TfmServer.Button1Click(Sender: TObject);
begin
mmLog.Lines.Add(PData(PThread(TCPServer.Threads.LockList.Items[0])^.Data)^.Name);
end;


Reindeer Moss Eater   (2004-03-11 09:31:00) [32]

Класс TidPeerThread.
У класса есть свойство Data : TObject.
В нем можно хранить указатель на TObject.
А можно и не хранить указатель на TObject, а хранить указатель на что душе угодно.
Например на твою record

PMyRecord = ^TMyRecord;
TMyRecord = record
MyName : string;
end;

var MyRec : TMyRecord;

AThread.Data := @MyRec;

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

Обратное преобразование:

ShowMessage('Поле MyName в записи TMyRecord имеет значение:' + PMyRecord(AThread.Data)^.MyName);


Gym   (2004-03-10 19:06:00) [33]


> Во второй строчке сверху.

Это в обработчик TForm1.FormCreate что-ли?


> Обычное приведение типов.
> Нужно привести TObject к типу указателя на RAcount


Дело в том, что у меня не слишком богатый опыт в этом
самом приведении типов, а так же в наследованиях всяких
и полиморфизмах. Не мог бы ты, что называется "на пальцах",
как для новичка, показать всё на примере. Я не прошу писать
и компилировать пример. Просто возми за основу листинг выложенный выше и расставь что где нужно (если не затруднит).
Спасибо.


Reindeer Moss Eater   (2004-03-10 09:00:00) [34]

Спасибо за ответ но,
Укажите, пожалуйста, в каком месте программы  нужно вставлять строку:

TidPeerThread.Data := TObject(@MyData);


Во второй строчке сверху.

И как потом обращаться к полям MyData.Name и MyData.Pwd?
А то у меня что-то ничего не получилось.


Обычное приведение типов.
Нужно привести TObject к типу указателя на RAcount


Gym   (2004-03-10 08:53:00) [35]

to Reindeer Moss Eater

Спасибо за ответ но,
Укажите, пожалуйста, в каком месте программы  нужно вставлять строку:

TidPeerThread.Data := TObject(@MyData);

И как потом обращаться к полям MyData.Name и MyData.Pwd?
А то у меня что-то ничего не получилось.

unit ServUnit;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdAntiFreezeBase, IdAntiFreeze, IdBaseComponent, IdComponent,
 IdTCPServer, StdCtrls;

type

 RAcount = record
   Name    : string;
   Pwd     : string;
 end;

 TForm1 = class(TForm)
   Memo1: TMemo;
   Button1: TButton;
   IdTCPServer1: TIdTCPServer;
   IdAntiFreeze1: TIdAntiFreeze;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
   procedure IdTCPServer1Connect(AThread: TIdPeerThread);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1  : TForm1;
 MyData : RAcount;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 idTCPServer1.Active:=True;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 idTCPServer1.Active:=False;
end;

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
var
 ThrList : TList;
begin
 Memo1.Lines.Add(AThread.Connection.Socket.Binding.PeerIP);
 Memo1.Lines.Add(IntToStr(AThread.ThreadID));
end;

end.


Reindeer Moss Eater   (2004-03-09 22:18:00) [36]

Ну во превых тем что я не знаю где он. :)Подскажите
пожалуйста.


TIdTCPServer.Threads

А во вторых я хочу хранить вместе со списком следующие поля:  

RAcount = record
  Thread  : TIdPeerThread;
  Name    : string;
  Pwd     : string;
end;


var
MyData : RAcount;

TidPeerThread.Data := TObject(@MyData);


S@shka   (2004-03-09 21:39:00) [37]

Это находиться в папке
Delphi6\Demos\Chat - то что тебе нужно на Indy :)


Gym   (2004-03-09 19:15:00) [38]


> Reindeer Moss Eater ©   (09.03.04 14:59) [5]
> Чем родной-то список созданных клиентских ниток не устраивает?


Ну во превых тем что я не знаюгде он. :)Подскажите
пожалуйста.
А во вторых я хочу хранить вместе со списком следующие поля:  

RAcount = record
   Thread  : TIdPeerThread;
   Name    : string;
   Pwd     : string;
end;

Что бы можно было сопоставить ID потока с ником и паролем.


Reindeer Moss Eater   (2004-03-09 14:59:00) [39]

Чем родной-тосписок созданных клиентских ниток не устраивает?


Gym   (2004-03-09 14:51:00) [40]

Удалено модератором
Примечание: Создание пустых сообщений ...


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо