Конференция "Сети" » список активных клиентов (Indy) [D7, WinXP]
 
  • GekaNaz (12.10.11 20:32) [0]
    Спасайте люди добрые :)
    пишу клиент-серверное приложение, клиенты общаются с сервером нормально, но требуется переодически сохранять данные о каждом юзере в базу данных,
    проблема в следующем- по таймеру 4 раза в минуту выполняется код:
     list:=serv.Contexts.LockList;
     for i:=0 to list.count-1 do
     begin
       q.SQL.Text:='update ClientTable set XXX=:dd where id=:id;';
       q.params[0].asinteger:=TMyData(TIdContext(List.Items[i]).Data).xxx;
       q.params[1].asinteger:=TMyData(TIdContext(List.Items[i]).Data).id;
       q.ExecSQL;
     end;
     serv.Contexts.UnlockList;

    это работает если клиент один.... или подключился второй.. третий и т.д... до тех пор пока один из них не отключится. свойство count выдает непонятное число .. оно иногда не меняется при отключении юзера, просто connection помечается как неактивное.
     А иногда при отключении второго юзера (из трех) count становится равным 2, а третий юзер на второе место не передвигается... и моя процедура по таймеру пытается постоянно писать в базу данных данные про неактивного второго юзера, а про третьего забывает..
  • Сергей М. © (12.10.11 20:51) [1]

    > xxx


    А это что за порно ?
  • Gekanaz (12.10.11 20:57) [2]
    есть блок данных в который записывается id из базы данных о приконнекченом юзере и еще некоторая инфа.... эта инфа переодически меняется клиентским соединением.... и её надо переодически сохранять в базу данных ... если вы знаете более интересный способ, то предложите
  • Gekanaz (12.10.11 20:59) [3]
    этот блок данных сохраняется в памяти (структура TMyData) у каждого нового коннекта есть указатель на данные  items[i].Data.. вот эти данные в цикле и надо сохранять, так как они очень важные , и ждать, пока клиент через пару дней отвалится... и по дисконнекту сохранять данные не логично...
  • Сергей М. © (12.10.11 21:00) [4]

    > при отключении второго юзера (из трех) count становится
    > равным 2, а третий юзер на второе место не передвигается


    С чего он передвинется-то, если ты сделал LockList списку коннектов ?
  • Gekanaz (12.10.11 21:08) [5]
    да нет, вы меня не поняли... клиент отключается гораздо раньше чем возникает эта процедура по таймеру, ставил таймер .. раз в 60 секунд.. все равно непонятки возникают. а как бы вы посоветовали считать данные о всех активных подключениях ?
  • Сергей М. © (12.10.11 21:10) [6]

    > клиент отключается


    А как этот фиксирует твой сервер ?
  • Gekanaz (12.10.11 21:11) [7]
    в обработчике ондисконнект  я вывожу в лог кто отключился... и больше ничего не делаю.. может в этом и ошибка
  • Gekanaz (12.10.11 21:15) [8]
    еще при отключении юзера нужно в базу данных сохранить последние актуальные данные, тут надо использовать походу пул коннектов к базе данных, это я еще пока незнаю как сделать
  • Сергей М. © (12.10.11 21:36) [9]
    > третий юзер на второе место не передвигается

    Чкм это подтверждается ?
  • Gekanaz (12.10.11 21:39) [10]
    в этом же цикле я добавляю имя клиента в Memo .. и вижу то, что выводится только первый и второй, который уже отключился... а до третьего дело не доходит, так как count уже=2
  • Gekanaz (12.10.11 21:42) [11]
    memo1.lines.clear;
    q.SQL.Text:='update ClientTable set XXX=:dd where id=:id;';//вынес из цикла

    for i:=0 to list.count-1 do
    begin
      q.params[0].asinteger:=TMyData(TIdContext(List.Items[i]).Data).xxx;
      q.params[1].asinteger:=TMyData(TIdContext(List.Items[i]).Data).id;
      q.ExecSQL;
      Memo1.lines.add(q.params[0].asinteger);
    end;
  • Сергей М. © (12.10.11 21:44) [12]
    А оно, это имя, откуда берется ?
    Из данных, ссылка на которые ты хранишь в Data ?
    Тогда это значит что данные об "имени" клиента не соответствуют действительности
  • Gekanaz (12.10.11 21:46) [13]
    именно там и храню, а где их хранить ?? когда создается подключение создается нить... к ней прикрепляется кусок данных, я создаю экземпляр в памяти.. и храню там данные.. когда происходит дисконнект , я очищаю память
  • Gekanaz (12.10.11 21:48) [14]
    TMyData = class //индивидуальные данные каждого коннекта
     public
       id:integer;//
       logg:boolean;//
       xxx : integer;
       Name : string;
     end;
  • Сергей М. © (12.10.11 21:49) [15]

    > когда создается подключение создается нить


    На сервере только что случился факт подключения, клиент еще НИЧЕГО не сказал серверу, а сервер уже знает имя клиента ?
    Чудеса)..
  • Gekanaz (12.10.11 21:54) [16]
    procedure TForm1.servConnect(AContext: TIdContext);
    begin
     memo1.Lines.Add('Connect='+Acontext.Connection.Socket.Binding.PeerIP+' \ '+DateTimeToStr(now));
     acontext.Data:=TmyData.Create;
     Tmydata(AContext.Data).logg:=false;
     Tmydata(AContext.Data).name:='еще не авторизован';
    end;

    procedure TForm1.servDisconnect(AContext: TIdContext);
    begin
      memo1.Lines.Add('Disconnect='+Acontext.Connection.Socket.Host);
    end;

    это две процедуры когда клиент коннектится, и отключается соответсвенно... в дисконнекте экземпляр данных не уничтожаю.. порылся в исходниках ,. вроде компонента сама удаляет экземпляр данных если он существует (  serv: TIdCmdTCPServer;)
  • Gekanaz (12.10.11 21:55) [17]
    нет, авторизация происходит следом за коннектом.. если такого юзера нет.. сразу отключение
  • Gekanaz (12.10.11 21:58) [18]
    это обработка команды сервера logging user password

    procedure TForm1.servCommandHandlers0Command(ASender: TIdCommand);
    begin

     q.SQL.Text:='select ID,XXX,B from client where nikname=:ni and pass=:pa';
     q.Params[0].Value:=asender.Params[0];
     q.Params[1].Value:=asender.Params[1];
     q.Open;
     if not q.Eof then
     begin  
       asender.Response.Add('USERDATA '+intToStr(Q.Fields[1].value)+' '+intToStr(q.Fields[2].value));
       Tmydata(asender.Context.Data).id:=Q.Fields[0].value;
       Tmydata(asender.Context.Data).xxx:=Q.Fields[1].value;
       Tmydata(asender.Context.Data).logg:=true;
       memo1.Lines.Add('Login '+asender.Params[0]+'='+Tmydata(asender.Context.Data).ip);
     end else
     begin// user not found
       asender.Response.Add('USERNULL 0');
     end;
    end;
  • Сергей М. © (12.10.11 21:59) [19]

    > в дисконнекте экземпляр данных не уничтожаю.. порылся в
    > исходниках ,. вроде компонента сама удаляет экземпляр данных
    > если он существует


    Как это "сама удаляет" ?
    Св-во Data - это нетипизированный указатель, откуда серверу знать что за ним кроется и как это "удалять" ?
  • Gekanaz (12.10.11 22:02) [20]

    > Как это "сама удаляет" ?
    > Св-во Data - это нетипизированный указатель, откуда серверу
    > знать что за ним кроется и как это "удалять" ?
    >
    >

    согласен с вами :)  , память почищу при дисконнекте методом destroy если не ошибаюсь, но думаю проблему это не решит
  • Сергей М. © (12.10.11 22:07) [21]

    > TMyData = class //индивидуальные данные каждого коннекта
    >  public
    >    id:integer;//
    >    logg:boolean;//
    >    xxx : integer;
    >    Name : string; // а это что ?
    >  end;
  • Gekanaz (12.10.11 22:12) [22]
    procedure TForm1.servCommandHandlers0Command(ASender: TIdCommand);
    //Name это имя юзера оно заполняется при авторизации
    Tmydata(asender.Context.Data).name:=asender.Params[0];
  • Сергей М. © (12.10.11 22:21) [23]
    в [18] приведен полный код обработчика команды.
    Что-то я в упор не вижу там ни единого обращения к св-ву Name ..
  • Gekanaz (12.10.11 22:24) [24]
    procedure TForm1.servCommandHandlers0Command(ASender: TIdCommand);
    begin

    q.SQL.Text:='select ID,XXX,B from client where nikname=:ni and pass=:pa';
    q.Params[0].Value:=asender.Params[0];
    q.Params[1].Value:=asender.Params[1];
    q.Open;
    if not q.Eof then
    begin  
      asender.Response.Add('USERDATA '+intToStr(Q.Fields[1].value)+' '+intToStr(q.Fields[2].value));
      Tmydata(asender.Context.Data).id:=Q.Fields[0].value;
      Tmydata(asender.Context.Data).xxx:=Q.Fields[1].value;
      Tmydata(asender.Context.Data).logg:=true;
      Tmydata(asender.Context.Data).name:=asender.Params[0]; // это было добавлено чуть позже...  а скопировалось из старого кода
      memo1.Lines.Add('Login '+asender.Params[0]+'='+Tmydata(asender.Context.Data).ip);
    end else
    begin// user not found
      asender.Response.Add('USERNULL 0');
    end;
    end;
  • Сергей М. © (12.10.11 22:34) [25]

    > в этом же цикле я добавляю имя клиента в Memo


    for i:=0 to list.count-1 do
    begin
     q.params[0].asinteger:=TMyData(TIdContext(List.Items[i]).Data).xxx; // !!!
    ...
     Memo1.lines.add(q.params[0].asinteger); // какое же это "имя клиента", если ты САМ сказал что имя клиента хранится в св-ве Name, а не в порно-свойстве ?
    end;
  • Gekanaz (12.10.11 22:50) [26]
    Memo1.lines.add(q.params[0].asinteger) - это дописывал от руки (полного кода с собой нет, поэтому ошибся
    Memo1.lines.add(TMyData(TIdContext(List.Items[i]).Data).name);  //это отладочная строка, потом будет удалена..
  • Сергей М. © (12.10.11 22:55) [27]
    т.е. ты утверждаешь что значения порносвойства xxx и св-ва Name в каждом объекте класса TMyData одинаковы и содердат имя клиента ?
  • Gekanaz (12.10.11 23:00) [28]
    for i:=0 to list.count-1 do
    begin
     q.params[0].asinteger:=TMyData(TIdContext(List.Items[i]).Data).xxx; //это порносвойство будет хранить количество коннектов :) этого клиента
     q.params[1].asinteger:=TMyData(TIdContext(List.Items[i]).Data).id;
     q.ExecSQL;
     Memo1.lines.add(TMyData(TIdContext(List.Items[i]).Data).name);  //это отладочная строка, потом будет удалена..
    end;

    xxx и name  даже разного типа и содержат разную инфу
  • Сергей М. © (12.10.11 23:13) [29]
    а где у тебя в обработчике servDisconnect() протоколирование имени отключившегося клиента ?
    не вижу ..
  • GekaNaz (13.10.11 08:21) [30]
    в [8] писал, что не сделал этого еще, но пока это не важно... я сам знаю, что я отключил Васю, почему Count не уменьшается вот это не понятно
  • Медвежонок Пятачок © (13.10.11 09:16) [31]
    при отключении юзера ставить флаг неактивности в его блоке данных.
    при обработке листа учитывать значение флага.
    локлист и анлок лист поместить в try/finally
  • Сергей М. © (13.10.11 09:40) [32]

    > я сам знаю, что я отключил Васю


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


    > почему Count не уменьшается


    Как это не уменьшается, если

    > подключился второй.. третий
    > при отключении второго юзера (из трех) count становится равным 2

    ?

    И не уменьшаться он НЕ может, если неопровержим факт возникновения события сервера OnDisconnect
  • Сергей М. © (13.10.11 09:50) [33]

    > Медвежонок Пятачок ©   (13.10.11 09:16) [31]
    >
    > при отключении юзера ставить флаг неактивности в его блоке
    > данных.


    Он нафих не нужен - с тем же успехом для этого достаточно проанализировать LockedList.Connection.Connected.
  • Сергей М. © (13.10.11 09:55) [34]
    > Медвежонок Пятачок
    К тому же автор утверждает что 2-й клиент из 3-х активных отключился еще при царе горохе - аж час назад,- и в течение часа список контекстов якобы не уменьшился.. Якобы как был равен 3-м, так и остался .. А этого не м.б. если при отключении 2-го клиента на сервере гарантированно возникло и было успешно обработано событие OnDisconnect.

    Потому что


    procedure TIdContext.AfterRun;
    begin
     if Assigned(OnAfterRun) then begin
       OnAfterRun(Self);
     end;

     if FContextList <> nil then begin
       FContextList.Remove(Self);
     end;
    end;

  • Сергей М. © (13.10.11 10:06) [35]

    > требуется переодически сохранять данные о каждом юзере в
    > базу данных


    Непонятная вообще затея..

    Для каждого коннекта сервер в ходе его обслуживания возбуждает кучу всякоразных событий, в контексте обработки которых можно легко и без выкрутасов с общим списком коннектов отреагировать на изменение состояния контекста этого коннекта.
  • GekaNaz (13.10.11 10:13) [36]
    вот весь код который работает также... ничего не поменялось, исправил все что советовали, список юзеров вывел в отдельный листбокс, в мемо1 идет лог коннектов и дисконнектов с отображением имени клиента
    ЧТО ТУТ НЕ ТАК ?

    procedure TForm1.servConnect(AContext: TIdContext);
    begin
     memo1.Lines.Add('Connect='+Acontext.Connection.Socket.Binding.PeerIP);
     acontext.Data:=TmyData.Create;
     Tmydata(AContext.Data).logg:=false;
     Tmydata(AContext.Data).name:='-';
    end;

    procedure TForm1.servDisconnect(AContext: TIdContext);
    begin
     memo1.Lines.Add(Tmydata(AContext.Data).name+'   Disconnect='+Acontext.Connection.Socket.Binding.PeerIP+' / '+DateTimeToStr(now));
     Tmydata(AContext.Data).Free;
     AContext.Data:=nil;
    end;

    procedure TForm1.servCommandHandlers0Command(ASender: TIdCommand);
    begin
     q.SQL.Text:='select ID,XXX,B from client where nikname=:ni and pass=:pa';
     q.Params[0].Value:=asender.Params[0];
     q.Params[1].Value:=asender.Params[1];
     q.Open;
     if not q.Eof then
     begin  
       asender.Response.Add('USERDATA '+intToStr(Q.Fields[1].value)+' '+intToStr(q.Fields[2].value));
       Tmydata(asender.Context.Data).id:=Q.Fields[0].value;
       Tmydata(asender.Context.Data).xxx:=Q.Fields[1].value;
       Tmydata(asender.Context.Data).logg:=true;
       memo1.Lines.Add(asender.Params[0]+'    =   Login');
       Tmydata(asender.Context.Data).name:=asender.Params[0];
     end else
     begin// user not found
       asender.Response.Add('USERNULL 0');
     end;
    end;

    procedure TForm1.Timer1Timer(Sender: TObject);
    var i,l,p,verrr:integer;
       f:double;
    begin
     lb1.items.Clear;
     if serv.Contexts <> nil then
     with serv.Contexts.LockList do try
     begin
       label1.Caption:=inttostr(count);  //здесь на форме смотрю сколько активных юзеров сейчас
       q.SQL.Text:='update client set XXX=:dd where id=:id;';
     if count>0 then
     for i:=0 to count-1 do
     begin
       if TIdContext(Items[i]).Connection.Connected then
       begin
        q.params[0].asinteger:=TMyData(TIdContext(Items[i]).Data).rur;
        q.params[1].asinteger:=TMyData(TIdContext(Items[i]).Data).id;
        q.ExecSQL;
                    lb1.Items.Add(TMyData(TIdContext(Items[i]).Data).name+' '+inttostr(q.params[0].asinteger));
       end else lb1.Items.Add('off '+TMyData(TIdContext(Items[i]).Data).name+' '+inttostr(q.params[0].asinteger));
     end;
     end;
     finally
       serv.Contexts.UnlockList;
     end;
     trans.Commit;//завершаем транзакцию
    end;
  • Сергей М. © (13.10.11 10:23) [37]
    Полные тексты протоколов приведи ..
  • GekaNaz (13.10.11 10:45) [38]
    LOGGIN username password  //команда авторизации
    QUIT  // disconnect

    :)  остальное пока не используется приводить смысла нет, да и остальной протокол еще в разработке
  • GekaNaz (13.10.11 10:47) [39]
    ответ на LOGGIN
    USERDATA xxx  // если авторизация успешна
    USERNULL 0   // если авторизация не прошла
  • Медвежонок Пятачок © (13.10.11 11:14) [40]
    таймер здесь не нужен.
    даже для таких странных желаний, что присходят у тебя в онтаймере.
  • Медвежонок Пятачок © (13.10.11 11:21) [41]
    вот зачем апдейтить чей-то XXX по таймеру значениями из его TMyData?

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

    у тебя процессору делать нечего или в комнате холодно и ты так греешся?
  • GekaNaz (13.10.11 11:29) [42]
    согласен, что могу по событию клиента писать в базу данных чтолибо, переделаю, мне нужно, чтобы я на сервере видел, кто сейчас на связи из клиентов, убираю весь код из таймера кроме вывода списка клиентов в листбокс... все равно не работает
  • GekaNaz (13.10.11 11:36) [43]
    коннектимся под моим ником... gekanaz,  в листбокс добавляется имя по таймеру...
    отключаемся... в листбоксе меняется надпись на "off gekanaz"
    цепляемся под другим ником... Dima...   в лисбоксе ничего не меняется... count =1
    затем отключаемся и только после этого видим "off Dima"

    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
    lb1.items.Clear;
    if serv.Contexts <> nil then
    with serv.Contexts.LockList do try
    begin
      label1.Caption:=inttostr(count);  //здесь на форме смотрю сколько активных юзеров сейчас
     if count>0 then
    for i:=0 to count-1 do
    begin
      if TIdContext(Items[i]).Connection.Connected then
             lb1.Items.Add(TMyData(TIdContext(Items[i]).Data).name+' '+inttostr(q.params[0].asinteger))
       else lb1.Items.Add('off '+TMyData(TIdContext(Items[i]).Data).name+' '+inttostr(q.params[0].asinteger));
    end;
    end;
    finally
      serv.Contexts.UnlockList;
    end;
    end;
  • Медвежонок Пятачок © (13.10.11 11:40) [44]
    мне нужно, чтобы я на сервере видел, кто сейчас на связи из клиентов

    для этого есть список клиентов и есть онконнект и ондисконнект.
    таймер здесь лишний
  • Медвежонок Пятачок © (13.10.11 11:41) [45]
    коннектимся под моим ником... gekanaz,  в листбокс добавляется имя по таймеру...
    отключаемся... в листбоксе меняется надпись на "off gekanaz"
    цепляемся под другим ником... Dima...   в лисбоксе ничего не меняется... count =1
    затем отключаемся и только после этого видим "off Dima"


    убери таймер.
  • GekaNaz (13.10.11 11:46) [46]
    то есть вы предлагаете по онконнекту в свою структуру данных добавлять нового клиента,,, а по дисконнекту его оттуда удалять ?? да еще и потокобезопасно... зачем изобретать велосипед, когда список уже есть у компонента TIDCMDTCPServer.
  • Медвежонок Пятачок © (13.10.11 11:47) [47]
    таймер убери.
  • GekaNaz (13.10.11 11:48) [48]
    если просто убрать таймер, тогда получится что два клиента одновременно могут коннектиться.. а листбокс это потоконебезопасный класс... и будет не гуд
  • Медвежонок Пятачок © (13.10.11 11:57) [49]
    убери таймер.
    а потокобезопасность решается через сендмессадж.
  • Anatoly Podgoretsky © (13.10.11 12:02) [50]
    Зато TThreadList потокобезопасный. И про какой протокол речь?
  • GekaNaz (13.10.11 12:06) [51]
    протокол самописный, экземпляр  TThreadList я создам и буду туда при коннекте и дисконнекте  добавлять и удалять оттуда юзеров... но непонятно зачем его писать если он есть в LockList-e
  • Медвежонок Пятачок © (13.10.11 12:08) [52]
    LockList это не лист а метод
  • GekaNaz (13.10.11 12:14) [53]
    это метод, с помощью которого я могу получить список активных клиентов ?? или нет.. это уже просто дело принципа.. разобраться.. то как это сделать
  • Медвежонок Пятачок © (13.10.11 12:20) [54]
    если дело принципа - то в одиночку.
    а здесь обычно помогают в разработке.
  • GekaNaz (13.10.11 12:22) [55]
    Понял, спасибо за помощь, просто непонятно, зачем он тогда нужен :)
  • Сергей М. © (13.10.11 12:23) [56]

    > убираю весь код из таймера


    Вместе с таймером, который нафих не нужен. Ни с какого боку не нужен.

    Тебе надо посмотреть в произвольный момент времени кто у тебя онлайн и под каким соусом ?

    Пройдись по списку контекстов, отбрасывая элементов Connection.Connected = False, бери свое св-во Data для каждого элемента - вот тебе и список активных клиентов.
  • Сергей М. © (13.10.11 12:26) [57]

    > это метод, с помощью которого я могу получить список активных
    > клиентов ?


    Это функуиональный метод, блокирующий доступ к списку активных контекстов (а не клиентов !!!!) со стороны других нитей сервера и возвращающий ссылку на этот список.
  • GekaNaz (13.10.11 12:49) [58]

    > Пройдись по списку контекстов, отбрасывая элементов Connection.
    > Connected = False, бери свое св-во Data для каждого элемента
    > - вот тебе и список активных клиентов.
    >

    with serv.Contexts.LockList do try
    for i:=0 to count-1 do
    begin
     if TIdContext(Items[i]).Connection.Connected then
            lb1.Items.Add(TMyData(TIdContext(Items[i]).Data).name)
    end;
    finally serv.Contexts.UnlockList; end;

    вот это я и пытался сделать... или тут есть ошибка ?
  • Сергей М. © (13.10.11 12:58) [59]

    > тут есть ошибка ?


    Тут ошибки нет.
  • Медвежонок Пятачок © (13.10.11 12:58) [60]
    Ошибка здесь дизайнерская. И она в том, что через пять минут после отладки тебе снова захочется прикрутить к этому коду таймер.
  • GekaNaz (13.10.11 13:01) [61]
    да нет.. таймер мне не нужен, а этот цикл не выдает список всех активных клиентов :(
  • Сергей М. © (13.10.11 13:16) [62]

    > тот цикл не выдает список всех активных клиентов


    А чего он выдает ?)
    Ты соизволишь наконец привести реальные данные протоколов отладочного логирования событий на сервере ?
  • GekaNaz (13.10.11 14:08) [63]
    написал класс потокобезопасный там храню копию данных из TMyData, по событию коннекта или дисконнекта обновляю список в листбоксе, все работает.

    TO Сергей М.
    а цикл который пробегается по локлисту выдает все тоже самое:
    connect  Вася
    Connect Петя
    Connect Дима

    цикл выдает всех трех юзеров...
    делаем дисконнект пети ( то есть он сам отключается)

    и теперь цикл выдает
    Вася  (коннектед)
    бывший петя (connected=false)  то есть цикл теперь проходит от 1 до 2 и выдает только васю.. так как петя уже не на связи, предполагаю что на 3 месте в листе есть и дима но имея число коннектов 2 до него дело не доходит
  • Сергей М. © (13.10.11 14:18) [64]
    между
    > делаем дисконнект пети ( то есть он сам отключается)

    и
    > и теперь цикл выдает

    должно произойти и быть полностью и успешно обработанным событие OnDisconnect с Петиным контекстом.

    Онго было ?
  • GekaNaz (13.10.11 14:45) [65]
    а разве в OnDisconnect  с контекстом чего-то надо делать ?, сейчас пока только пишется в лог.. что этот клиент отконнектился... , я порылся в примерах там , вроде ничего не делают, только в лог пишут и все
  • Сергей М. © (13.10.11 15:07) [66]

    > разве в OnDisconnect  с контекстом чего-то надо делать ?


    А как же !?
    Клиент же отвалился, объект Data (читай - твоё прикладное расширение контекста существовавшего до этого коннекта), описывающий параметры клиента (пусть даже и не залогинившегося), более не актуален, его следует тут же в обработчике дисконнекта и уничтожить, потому что после возврата из OnDisconnect индейский объект-контекст будет разрушен, причем в ходе своего разрушения он удалит сам себя из указанного ему списка контекстов (см. [34])
  • Anatoly Podgoretsky © (13.10.11 15:25) [67]
    Вместо разреженых массивов, в данном случае используются какие либо списки. Достаточно посмотреть примеры по ICS они все построены на списков и объекты идентифицируются без каких либо дополнительных ИД
  • Anatoly Podgoretsky © (13.10.11 16:43) [68]
    > GekaNaz  (13.10.2011 14:08:03)  [63]

    Если connected=false, то почему же ты его не удалил из списка.
  • Сергей М. © (13.10.11 16:49) [69]

    > Anatoly Podgoretsky ©   (13.10.11 16:43) [68]


    > почему же ты его не удалил из списка.


    зачем его удалять-то, если см. [34] ?
 
Конференция "Сети" » список активных клиентов (Indy) [D7, WinXP]
Есть новые Нет новых   [134435   +19][b:0.001][p:0.002]