![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TIdTCPServer + несколько клиентов. [D7]
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]Удалено модератором
Примечание: Создание пустых сообщений ...