![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TIdCmdTCPServer
Zalm © (2009-08-31 13:14:00)Здравствуйте, как у TIdCmdTCPServer можно всем клиентам разослать сообщение? Надо например каждому отослать команду. Это должно быть естественно в цикле, только я не знаю как и где. У TServerSocket было проще всё, ну или понятней.
1)Вот например у меня есть кнопка на сервере, как сделать чтоб ы при нажатии на кнопку каждому подключению что-то отправить, и что бы узнать его адрес там и тд?
2) Как узнать ip и handler подключения? и в каком евенте... если в OnConnect то я не опнля как...
3) Как вне событий отправить текст на подключение с известным адресом\обработчкиом?
Буду очень благодарен за помощь.
Zalm (2009-09-19 22:23:00) [21]
> неправильно. причем неправильно не из за секций.
а почему не сказал из-за чего :(
Сергей, вы так и не сказали секции правильно или нет...
Про try..finally слышал, я его обычно для ошибок использую Try..Except
Anatoly Podgoretsky (2009-09-19 20:48:00) [22]> Сергей М. (19.09.2009 15:23:08) [128]
select from insert to
"Сергей М."
сообщил/сообщила в
новостях следующее:
news:1251710046.128@delphimaster.ru...
Сергей М. © (19.09.2009 15:23) [128]
> edit1.Text
Это тоже
потоконебезопасное
обращение.
Ты, кстати, про try..finally
что-нибудь слышал ?
Сергей М. (2009-09-19 15:23:00) [23]
> edit1.Text
Это тоже потоконебезопасное обращение.
Ты, кстати, проtry..finallyчто-нибудь слышал ?
Медвежонок Пятачок (2009-09-19 01:30:00) [24]неправильно. причем неправильно не из за секций.
Zalm (2009-09-19 01:25:00) [25]
> Чего ж ты тогда продолжаешь топик и постишь код, при котором
> "всем стало хорошо" ?)
))))
Так с крит секциями правильно?
procedure TForm1.ServerConnect(AContext: TIdContext);
var
str, IP : string;
I : integer;
Port:Word;
KEY_CHECK : String;
begin
KEY_CHECK:=Acontext.Connection.Socket.Readln();
if edit1.Text<>KEY_CHECK then Acontext.Connection.Disconnect;
AContext.Connection.Socket.Writeln('Index[<=10]');
str:=Acontext.Connection.Socket.ReadLn();
if length(str)>10 then Acontext.Connection.Disconnect;
CriticalSection.Enter;
for I := 0 to Clients.Count - 1 do
begin
if Clients.Clients[i].Index=str then
begin
if Clients.Clients[i].SIP='' then
begin
Clients.Clients[i].SIP:=Acontext.Connection.Socket.Binding.PeerIP;
Clients.Clients[i].SPort:=AContext.Connection.Socket.Binding.PeerPort;
Acontext.Connection.Socket.WriteLn('srd');
CriticalSection.Leave;
exit;
end;
if Clients.Clients[i].PIP='' then
begin
Clients.Clients[i].PIP:=Acontext.Connection.Socket.Binding.PeerIP;
Clients.Clients[i].PPort:=AContext.Connection.Socket.Binding.PeerPort;
Acontext.Connection.Socket.WriteLn('srd');
CriticalSection.Leave;
exit;
end;
AContext.Connection.Disconnect;
CriticalSection.Leave;
exit;
end;
end;
inc(Clients.Count);
SetLength(Clients.Clients,Clients.Count);
Clients.Clients[Clients.Count-1].SIP:=AContext.Connection.Socket.Binding.PeerIP;
Clients.Clients[Clients.Count-1].SPort:=AContext.Connection.Socket.Binding.PeerPort;
Clients.Clients[Clients.Count-1].Index:=str;
CriticalSection.Leave;
Acontext.Connection.Socket.WriteLn('srd');
end;
Сергей М. (2009-09-18 17:21:00) [26]
> так дело никуда не сдвинется
Конечно не сдвинется..
Думать-то ты по-прежнему не хочешь..
> с ним вылазили ошибки, а без него всем стало хорошо
Чего ж ты тогда продолжаешь топик и постишь код, при котором "всем стало хорошо" ?)
Zalm (2009-09-18 17:16:00) [27]
> Я ж палец сломаю, если буду в каждую тыкать : весь этот
> код - одна сплошная большая ошибка)
ну так дело никуда не сдвинется... не хорошо так..
> Вот скажи, ты за каким создал объект CriticalSection, если
> нигде кроме как в Form1.OnCreate его в последствии не используешь
> для защиты ресурса Clients ?
Раньше использховал, в ONConnect и OnDisconnect, но с ним вылазили ошибки, а без него всем стало хорошо xD
Я попробую это исправить.
Сергей М. (2009-09-18 17:06:00) [28]Я ж палец сломаю, если буду в каждую тыкать : весь этот код - одна сплошная большая ошибка)
Вот скажи, ты за каким создал объект CriticalSection, если нигде кроме как в Form1.OnCreate его в последствии не используешь для защиты ресурса Clients ?
И от кого ты защищаешь ресурс Clients при обработке события Form1.OnCreate, если в этот момент не существует ни единого потока кроме основного ?
Zalm (2009-09-18 16:53:00) [29]
Procedure Server_clear;
var
list : TList;
i : integer;
begin
try
LIst:=Form1.Server.Contexts.LockList;
for I := 0 to List.Count - 1 do
with TidContext(List[i]) do Connection.Disconnect;
finally
Form1.Server.Contexts.UnlockList;
end;
Clients.Count:=0;
SetLength(Clients.Clients,0);
end;
procedure TForm1.ServerExecute(AContext: TIdContext);
var
MSG : string;
I, J : integer;
List : Tlist;
_ip : string;
_port : word;
key : string;
begin
msg:=AContext.Connection.Socket.ReadLn();
{----------------------------------------}
if msg='\reset\' then
begin
Server_clear;
end;
if msg='\сhKOL\' then
begin
end;
if msg='\chKEY\' then
begin
AContext.Connection.Socket.Writeln('KEY');
key:=AContext.Connection.Socket.Readln();
if KEY<>Edit2.Text then
begin
AContext.Connection.Socket.WriteLn('ikr'); {invalid key read}
Acontext.Connection.Disconnect;
exit;
end
else
begin
AContext.Connection.Socket.WriteLn('NK'); {new key}
KEY:=AContext.Connection.Socket.ReadLn();
if Length(key)>10 then
begin
AContext.Connection.Socket.WriteLn('iks'); {invalid key set}
AContext.Connection.Disconnect;
exit;
end
else
begin
Acontext.Connection.Socket.Write('oks'); {ok key set}
Edit1.Text:=key;
exit;
end;
end;
end;
if msg='\clients\' then
begin
Acontext.Connection.Socket.WriteLn(IntToStr(Clients.Count));
exit;
end;
if msg='\exit\' then
begin
AContext.Connection.Disconnect;
exit;
end;
if msg='\data\' then
begin
for i := 0 to Clients.Count - 1 do
begin
Acontext.Connection.Socket.WriteLn('SIP: '+Clients.Clients[i].SIP);
AContext.Connection.Socket.WriteLn('SPort: '+IntToStr(Clients.Clients[i].SPort));
AContext.Connection.Socket.WriteLn('PIP: '+Clients.Clients[i].PIP);
AContext.Connection.Socket.WriteLn('PPort: '+IntToStr(Clients.Clients[i].PPort));
AContext.Connection.Socket.WriteLn('Index: '+Clients.Clients[i].Index);
end;
exit;
end;
if msg='\i\' then
begin
AContext.Connection.Socket.WriteLn(AContext.Connection.Socket.Binding.PeerIP+':'+IntToStr(AContext.Connection.Socket.Binding.PeerPort));
exit;
end;
{----------------------------------------}
for i := 0 to Clients.Count - 1 do
begin
if ((Clients.Clients[i].SIP=AContext.Connection.Socket.Binding.PeerIP)and(Clients.C lients[i].SPort=AContext.Connection.Socket.Binding.PeerPort))or
((Clients.Clients[i].PIP=Acontext.Connection.Socket.Binding.PeerIP)and(Clients.C lients[i].PPort=AContext.Connection.Socket.Binding.PeerPort)) then
begin
if (Clients.Clients[i].SIP=AContext.Connection.Socket.Binding.PeerIP)and
(Clients.Clients[i].SPort=AContext.Connection.Socket.Binding.PeerPort) then
begin
_ip:=Clients.Clients[i].PIP;
if _ip='' then
begin
AContext.Connection.Socket.WriteLn('No send.');
exit;
end;
_port:=Clients.Clients[i].PPort;
Send(_ip,_port,msg);
exit;
end
else
begin
_ip:=Clients.Clients[i].SIP;
if _ip='' then
begin
AContext.Connection.Socket.WriteLn('No send.');
exit;
end;
_port:=Clients.Clients[i].SPort;
Send(_ip,_port,msg);
exit;
end;
end
else
begin
end;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
form2.show;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
Application.Terminate;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
Tray.Visible:=True;
Form1.Hide;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
day : integer;
pmc:PPROCESS_MEMORY_COUNTERS;
begin
cl.Caption:=IntToStr(Clients.Count*2);
Start_time.Caption:=TimeToStr(_Start_time);
if Abs(_Start_time-now)>1 then
begin
day:=Abs(Trunc(_Start_time-now));
form1.work_time.Caption:=FloatToStr(day)+' д. '+TimeToStr(_Start_time-now);
end
else form1.work_time.Caption:=TimeToStr(now-_Start_time);
GetMem(pmc, SizeOf(_PROCESS_MEMORY_COUNTERS));
pmc.cb:=SizeOf(_PROCESS_MEMORY_COUNTERS);
If GetProcessMemoryInfo(GetCurrentProcess(), pmc, pmc.cb) then
begin
ram.Caption:=FloatToStrF((pmc^.WorkingSetSize)/1024/1024,ffFixed,15,3)+' Мб';
FreeMem(pmc);
end;
end;
procedure TForm1.TrayClick(Sender: TObject);
begin
Form1.Show;
Tray.Visible:=False;
end;
Procedure Send (ip:string;port:word;str:string);
var
i : integer;
List : Tlist;
begin
try
LIst:=Form1.Server.Contexts.LockList;
for I := 0 to List.Count - 1 do
with TidContext(List[i]) do
begin
if (connection.Socket.Binding.PeerIP=ip)and(connection.Socket.Binding.PeerPort=port ) then
begin
TidCOntext(list[i]).Connection.Socket.WriteLn(str);
break;
end;
end;
finally
Form1.Server.Contexts.UnlockList;
end;
end;
Zalm (2009-09-18 16:52:00) [30]
> нельзя использовать тип string generic, а не fundamental
а побольше про это слов скажете?)
Сергей, прошу тыкать пальцем, где ошибки
_Pack = record
SIP : string[15];
SPort : WORD;
PIP : string[15];
PPort : Word;
Index : String[10];
end;
_Clients = class
pack : _pack;
Clients : Array of _pack;
Count : integer;
end;
Procedure Send (ip:string;port:word;str:string);
Procedure Server_clear;
var
Link_file : TEXTFILE;
RAM_file : TEXTFILE;
Form1: TForm1;
Clients : _Clients;
_null : _pack;
CriticalSection : TCriticalSection;
_Start_time : TDATETIME;
Last_ram : real;
implementation
{$R *.dfm}
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Server.StopListening;
APPLICATION.Terminate;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AssignFIle(Link_file,'link.sf');
AssignFIle(RAM_file,'ram.sf');
Rewrite(link_file);
Rewrite(ram_file);
CloseFile(link_file);
CloseFile(Ram_file);
_Start_time:=now;
CriticalSection:=TCriticalSection.Create;
CriticalSection.Enter;
Clients:=_Clients.Create;
CriticalSection.Leave;
Server.MaxConnections:=Limits.Value;
cl_limit.Caption:=IntTOstr(limits.Value);
end;
procedure TForm1.limitsClick(Sender: TObject);
begin
Server.MaxConnections:=Limits.Value;
cl_limit.Caption:=IntToStr(limits.Value);
end;
procedure TForm1.logTimer(Sender: TObject);
Var
pmc:PPROCESS_MEMORY_COUNTERS;
rm : real;
state : string;
begin
state:='';
Append(ram_file);
GetMem(pmc, SizeOf(_PROCESS_MEMORY_COUNTERS));
pmc.cb:=SizeOf(_PROCESS_MEMORY_COUNTERS);
If GetProcessMemoryInfo(GetCurrentProcess(), pmc, pmc.cb) then rm:=(pmc^.WorkingSetSize)/1024/1024;
if (rm>last_ram) then
begin
state:='+'+FloatToStrF(rm-Last_ram,ffFixed,15,3);
end;
if (rm<last_ram) then
begin
state:='-'+FloatToStrF(last_ram-rm,ffFixed,15,3);
end;
if rm=last_ram then State:='0';
Last_ram:=rm;
Writeln(ram_file,DateToStr(now)+' '+TimeToStr(now)+' \ RAM: '+FloatTOStrF(rm,ffFixed,15,3)+'\ '+state);
CloseFile(ram_file);
end;
procedure TForm1.displayClick(Sender: TObject);
var
str : string;
begin
RichEdit1.Clear;
if display.ItemIndex=0 then
begin
RichEdit1.Lines.Add('not supported');
end;
if display.ItemIndex=1 then
begin
reset(ram_file);
while not(eof(ram_file)) do
begin
readln(ram_file,str);
RichEdit1.Lines.Add(str);
end;
RichEdit1.Lines.Add('---------------------'+#13+' END');
closeFIle(ram_file);
end;
end;
procedure TForm1.ServerConnect(AContext: TIdContext);
var
str, IP : string;
I : integer;
Port:Word;
KEY_CHECK : String;
begin
KEY_CHECK:=Acontext.Connection.Socket.Readln();
if edit1.Text<>KEY_CHECK then Acontext.Connection.Disconnect;
AContext.Connection.Socket.Writeln('Index[<=10]');
str:=Acontext.Connection.Socket.ReadLn();
if length(str)>10 then Acontext.Connection.Disconnect;
for I := 0 to Clients.Count - 1 do
begin
if Clients.Clients[i].Index=str then
begin
if Clients.Clients[i].SIP='' then
begin
Clients.Clients[i].SIP:=Acontext.Connection.Socket.Binding.PeerIP;
Clients.Clients[i].SPort:=AContext.Connection.Socket.Binding.PeerPort;
Acontext.Connection.Socket.WriteLn('srd');
exit;
end;
if Clients.Clients[i].PIP='' then
begin
Clients.Clients[i].PIP:=Acontext.Connection.Socket.Binding.PeerIP;
Clients.Clients[i].PPort:=AContext.Connection.Socket.Binding.PeerPort;
Acontext.Connection.Socket.WriteLn('srd');
exit;
end;
AContext.Connection.Disconnect;
exit;
end;
end;
inc(Clients.Count);
SetLength(Clients.Clients,Clients.Count);
Clients.Clients[Clients.Count-1].SIP:=AContext.Connection.Socket.Binding.PeerIP;
Clients.Clients[Clients.Count-1].SPort:=AContext.Connection.Socket.Binding.PeerPort;
Clients.Clients[Clients.Count-1].Index:=str;
Acontext.Connection.Socket.WriteLn('srd');
end;
procedure TForm1.ServerDisconnect(AContext: TIdContext);
var
i, j : integer;
begin
for i := 0 to Clients.Count - 1 do
begin
if (Clients.Clients[i].SIP+':'+IntToStr(Clients.Clients[i].SPort)=AContext.Connection.Socket.Binding.PeerIP+':'+IntToStr(AContext.Connection.Socket.Binding.PeerPort)) then
begin
Clients.Clients[i].SIP:='';
Clients.Clients[i].SPort:=0;
break;
end;
if (Clients.Clients[i].PIP+':'+IntToStr(Clients.Clients[i].PPort)=AContext.Connection.Socket.Binding.PeerIP+':'+IntToStr(AContext.Connection.Socket.Binding.PeerPort)) then
begin
Clients.Clients[i].PIP:='';
Clients.Clients[i].PPort:=0;
break;
end;
end;
if (clients.Clients[i].SIP='')and(clients.Clients[i].PIP='') then
begin
for j := i to clients.Count - 1 do
Clients.Clients[j]:=Clients.Clients[j+1];
dec(clients.Count);
SetLength(clients.Clients,Clients.Count);
end;
end;
Anatoly Podgoretsky (2009-09-18 13:34:00) [31]
> MSG : string;
> I, J : integer;
> List : Tlist;
> _ip : string;
> _port : word;
> key : string;
Слова плохие будут, вот здесь плохие имена, почти все, ну ладно это дело компилятора, а вот типы уже не дело компилятора - нельзя использовать тип string generic, а не fundamental - особенно для сетевых протоколов. В Инди с этим уже много дел натворили.
Сергей М. (2009-09-18 08:18:00) [32]
> Такое у меня уже есть
Выкинь в топку.
Абсолютно бестолковый код.
> в других местах почему-то лаги
У тебя ошибки в программе.
Zalm (2009-09-17 20:33:00) [33]
> Но тогда и гонор знайки совсем неуместен)
вот этого не понял
> Алгоритм простой:
> 1. Войти в крит.секцию.2. Обратиться к
> ресурсу.3. Выйти из крит.секции.
Всё было бы шикарно если бы не было бы затыков. Такое у меня уже есть.
procedure TForm1.FormCreate(Sender: TObject);
begin
_Start_time:=now;
CriticalSection:=TCriticalSection.Create;
CriticalSection.Enter;
Clients:=_Clients.Create;
CriticalSection.Leave;
Server.MaxConnections:=Limits.Value;
cl_limit.Caption:=IntTOstr(limits.Value);
end;
Да вот только в других местах почему-то лаги, если обращаться через крит секцию то иногда выдает ошибки памяти или вобще потом программа не выключается нормально, только в процессах убивать если
Сергей М. (2009-09-17 19:59:00) [34]И все-таки ты занимаешься откровенной херней.
Если это учебнаязадача, то она еще как-то оправдана в реализации.
Но тогда и гонор знайки совсем неуместен)
Если же не учебная, то достаточно попросить админа пробросить порт на твой хост. На своем хосте ты волен развернуть хоть VPN, хоть черта лысого)
Сергей М. (2009-09-17 19:48:00) [35]Алгоритм простой:
1. Войти в крит.секцию.
2. Обратиться к ресурсу.
3. Выйти из крит.секции.
Zalm (2009-09-17 19:42:00) [36]нет, ну просто алгоритм скажите пожалуйста как делать
Сергей М. (2009-09-17 19:32:00) [37]В смысле ?
Программу что ли за тебя написать ?
Zalm (2009-09-17 17:44:00) [38]
> > Процедуры подключения и отключения клиентов используют
> один > и тот же массив, что будет когда неск клиентов столкнутся
> > на одном и том же массиве, в том смысле то есть что он
> им > обоим будет нужен сразу?Грабли будут.Доступ к потоконебезопасному
> ресурсу обязателен к синхронизации.> что будет если кто-
> то из клиентов соберется что-то отправить,> в то время
> как УЖЕ будет работать процедура Send вызванная > предыдущим
> клиентом?Этот "кто-то" застрянет на LockList до тех пор,
> пока предыдущий "кто-то" не вызовет UnlockList.
и как мне всё это исправить что бы было как надо?
Сергей М. (2009-09-17 17:23:00) [39]
> Сервер не предназначем для чата
Фиолетово для чего он предназначен.
Преведбыл выбран как абстрактный пример некоего инф.сообщения, которое может трактоваться неоднозначно.
> Трафик между парами определен протоколом другим
Ну и нафих это надо - месить два протокола там где место одному ?
<код команды серверу>[<параметры команды серверу>]
В <параметры команды серверу> пиши что угодно, в т.ч. команды другого протокола, ибо серверу на них начхать - он понимает и трактует только своикоманды.
Например,
Команда - SendCmdToPeer
Параметры: PeerID, CmdCode, CmdParams
Команда - RecvResponceFromPeer
Параметры: PeerID, CmdRequestID
Сергей М. (2009-09-17 17:01:00) [40]
> Процедуры подключения и отключения клиентов используют один
> и тот же массив, что будет когда неск клиентов столкнутся
> на одном и том же массиве, в том смысле то есть что он им
> обоим будет нужен сразу?
Грабли будут.
Доступ к потоконебезопасному ресурсу обязателен к синхронизации.
> что будет если кто-то из клиентов соберется что-то отправить,
> в то время как УЖЕ будет работать процедура Send вызванная
> предыдущим клиентом?
Этот "кто-то" застрянет на LockList до тех пор, пока предыдущий "кто-то" не вызовет UnlockList.