Конференция "Сети" » Проблемма TIdTCPServer [D7, WinXP]
 
  • PonosetcDM © (17.06.10 09:24) [0]
    Проблемма следующая:
      Есть TIdTCPClient на одной форме и TIdTCPServer на другой,
    устанавливаю подключение, вес в порядке...
      1й случай: Клиент шлет серверу сообщения, шлет раз, шлет два.... все гут, делаю  дисконнект, коннект, все окей опять шлю и все принимается все нормуль...
     2й случай: клиент послал серверу сообщение, сервер его обработал, все гут, потом сервер шлет клиенту сообщение, клиент его принимает... все казалось бы Ок, но если после того, как сервер отправляет сообщение клиенту, и потом я делаю клиенту дисконнект, то ничё больше не работает, делаю клиентом повторный коннект, он пишет типа подсоединился, но сообщения больше не обрабатываются на сервере и сам сервер не может ниче послать грит ошибка "Connection Closed Grasfully" и все... как это решить... Помогите плиииз...
    P.S. использую Delphi 7 и Indy 10.1.5,
         отправка сообщений:
           Клиент: IdTCPClient1.Socket.WriteLn
          Сервер:TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.Wri teLn
  • PonosetcDM © (17.06.10 09:25) [1]
    Кстати всем превет! Заранее спс...
  • Сергей М. © (17.06.10 09:29) [2]
    У тебя ошибка в программе.
  • PonosetcDM © (17.06.10 09:41) [3]
    ВОт так обрабатываю сообщения на сервере:

    procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
    var recvfs: TFileStream;
      i, cp : byte;
      tmsg : TPackage;
      Buf : TIdBytes;
    begin
     tmsg.fHeader.totalSize := StrToInt64(AContext.Connection.Socket.ReadLn);
     AContext.Connection.Socket.ReadBytes( Buf , tmsg.fHeader.totalSize );
     ZeroMemory(@tmsg,sizeof(tmsg));
     tmsg.fHeader.cmd := Buf[0];
     tmsg.fHeader.ParamCount := Buf[1];

     Move ( Buf[2] , Cardinal(tmsg.fHeader.totalSize) , sizeof(cardinal) );

     SetLength(tmsg.fHeader.ParamsLength , tmsg.fHeader.ParamCount);
     if tmsg.fHeader.ParamCount > 0 then
       Move( Buf[2 + SizeOf(cardinal)] , tmsg.fHeader.ParamsLength[0] , tmsg.fHeader.ParamCount * SizeOf(Cardinal) );

     SetLength( tmsg.fData.Params , tmsg.fHeader.ParamCount );
     if tmsg.fHeader.ParamCount > 0 then
     begin
       SetLength( tmsg.fData.Params[0] , tmsg.fHeader.Paramslength[0] );
       cp := 2 + SizeOf(cardinal) + tmsg.fHeader.ParamCount * Sizeof(cardinal);
       Move( Buf[cp] , tmsg.fData.Params[0][1] , tmsg.fHeader.Paramslength[0] );
       for i := 1 to tmsg.fHeader.ParamCount - 1 do
       begin
         inc( cp , tmsg.fHeader.Paramslength[i - 1] );
         SetLength( tmsg.fData.Params[i] , tmsg.fHeader.Paramslength[i] );
         Move( Buf[cp] , tmsg.fData.Params[i][1] , tmsg.fHeader.Paramslength[i] );
       end;
     end;
     Memo1.Lines.Add('*********** We have a new message*******');
     Memo1.Lines.Add('   Message CMD Code = ' + IntToStr(tmsg.fHeader.cmd));
     Memo1.Lines.Add('   Message Params: ');

     if tmsg.fHeader.paramCount>0 then
     for i := 0 to tmsg.fHeader.ParamCount - 1 do
       Memo1.Lines.Add('      ' + (tmsg.fData.Params[i]));
     
     Case tmsg.fHeader.cmd of
       CMD_CONNECTION_STR :  Memo1.Lines.Add('We have a new connection...');
       CMD_MESSAGE        :  Memo1.Lines.Add('This is a message');
       CMD_FILE_UPLOAD :begin
                          recvfs:= TFileStream.Create(ExtractFileName(tmsg.fData.Params[0])+'.tmp',fmCreate);
                          AContext.Connection.Socket.ReadStream(recvfs,StrToInt(tmsg.fData.Params[1]),fals e);
                          Memo1.Lines.Add('-----> New File upload complete...');
                        end;
    {    CMD_DISCONNECT:begin
                        AContext.Connection.Disconnect;
                      end;     {}
     end;

     Memo1.Lines.Add('*********** End of new message*******');
     
    end;

     TPackageHeader = record
       cmd : byte;
       ParamCount : byte;
       totalSize : cardinal;
       ParamsLength : array of cardinal;
     end;

     TPackageData = record
       Params:array of string;
     end;

     TPackage = record
       fHeader : TPackageHeader;
       fData : TPackageData;
     end;

    Сообщения сервер отправляет так:

    procedure TForm1.SendPackage(pcmd, pparamCount: byte;
     pparams: array of string);
    var tmsg : TPackage;
       i : integer;
       buf : TIdBytes;
    begin
    //
    //  buf:=@tmsg;
     ZeroMemory(@tmsg,sizeof(tmsg));
     tmsg.fHeader.cmd := pcmd;
    //  tmsg.fHeader.totalSize := sizeof(tmsg.fHeader.cmd);

     tmsg.fHeader.ParamCount := pparamCount;
    //  tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + sizeof(tmsg.fHeader.ParamCount);

    //  tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + sizeof(tmsg.fHeader.totalSize);

     SetLength(tmsg.fHeader.ParamsLength,pparamCount);
    //  tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + length(tmsg.fHeader.ParamsLength)*Sizeof(cardinal);
     SetLength(tmsg.fData.Params,pparamCount);

     for i := 0 to pparamCount-1 do begin
       SetLength(tmsg.fData.Params[i],length(pparams[i]));
       Move(pparams[i][1],tmsg.fData.Params[i][1], length(pparams[i]));
       tmsg.fHeader.ParamsLength[i]:= length(tmsg.fData.Params[i]);
       tmsg.fHeader.totalSize:= tmsg.fHeader.totalSize + length(tmsg.fData.Params[i]) ;
     end;

     tmsg.fHeader.totalSize :=  tmsg.fHeader.totalSize+
                               Sizeof(tmsg.fHeader.cmd)+
                               Sizeof(tmsg.fHeader.totalSize)+
                               Sizeof(tmsg.fHeader.ParamCount)+
                               Length(tmsg.fHeader.ParamsLength)*SizeOf(Cardinal);

     SetLength(Buf, tmsg.fHeader.totalSize);
     Move(tmsg.fHeader.cmd, buf[0], 1);
     Move(tmsg.fHeader.ParamCount, buf[1], 1);
     Move(cardinal(tmsg.fHeader.totalSize), buf[2], sizeof(cardinal));

     if pparamCount>0 then
     for i := 0 to pparamCount-1 do
      Move(tmsg.fHeader.ParamsLength[i], buf[6+i*Sizeof(Cardinal)], SizeOf(Cardinal));

     if pparamCount>0 then
     begin
       Move(tmsg.fData.Params[0][1], buf[6+pParamCount*Sizeof(Cardinal)], length(tmsg.fData.Params[0]));
       for i := 1 to pparamCount-1 do
        Move(tmsg.fData.Params[i][1], buf[6+pParamCount*Sizeof(Cardinal)+Length(tmsg.fData.Params[i-1])], length(tmsg.fData.Params[i]));
     end;
     TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.WriteLn(In tToStr(tmsg.fHeader.totalSize));
     TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.Write(Buf) ;
    end;
  • PonosetcDM © (17.06.10 09:44) [4]
    У клиента почти таже бадяга, но тока сообщения обрабатываются в таймере(как показано в Demosах):

    procedure TForm1.Timer1Timer(Sender: TObject);
    var i:integer;
       s:string;
    begin
     if not IdTCPClient1.Connected then exit;

     i:=IdTCPClient1.IOHandler.InputBuffer.Size;
     if i>0 then GetNewMessages;
    end;

    GetNewMessages почти тот же код, что и у procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
  • Сергей М. © (17.06.10 09:53) [5]
    Очевидных безобразий ы твоем коде явно не одно.

    Взять хотя бы это:


    > ZeroMemory(@tmsg,sizeof(tmsg));


    С учетом типа поля Params:array of string обнуление этого поля недопустимо.
  • PonosetcDM © (17.06.10 09:59) [6]
    Ну про эту строчку вообще забыть можно... она сути проблеммы не меняет...
    Заменим её на   tmsg.fHeader.cmd:=0;   tmsg.fHeader.ParamCount:=0;   tmsg.fHeader.totalSize:=0;
  • Сергей М. © (17.06.10 10:25) [7]
    Воспользуйся встроенным отладчиком.
  • PonosetcDM © (17.06.10 11:07) [8]
    Я пользовался уже вчера им весь день, Buf заполняется идеально, tmsg заполняется идеально, дошел до самых низов Indy т.сказать все идеально, кол-во отправленных байт идеально, я уже от безысходности тут пишу, никогда нигде не отписывал... Если хочешь я тебе на мыло пришлю исходники, сам протестишь...???
  • Сергей М. © (17.06.10 12:09) [9]

    > Если хочешь


    Не хочу.
    Оно мне надо ?)

    Факт-то налицо - отказ с диагностикой Connection Closed Grasfully возникает когда партнер по соединению закрывает его со своей стороны по своей же инициативе.
  • PonosetcDM © (17.06.10 12:31) [10]
    Праааально гришь, эта ошибка вылетает у TIdTCPServer значит клиент разорвал соединение, чтож все верно, но почиму она возникает только после того, как я с сервера пошлю клиенту сообщение???

    Если Сервер ничего не посылает за сеанс клиенту, то клиент может коннектится и дисконнектится, и передавать серверу сообщения скока угодно раз... А стоит клиенту подключиться, серверу отправить сообщение, клиенту отключиться, клиенту подключиться, как УСЁ "Кирдык".... в чем прикол та??
  • Сергей М. © (17.06.10 12:34) [11]

    > в чем прикол та?


    Сказал ведь уже - у тебя ошибка в программе.
    Судя по [10] - в программе клиента.
  • PonosetcDM © (17.06.10 12:35) [12]
    Может я дисконнект у клиента неправильно делаю, может там что-ть ещё очищать надо?? ну эт савсем нонсенс был бы....
  • Сергей М. © (17.06.10 12:43) [13]

    > PonosetcDM ©   (17.06.10 12:35) [12]


    Таймер-то на стороне клиента нафих понадобился ?)
  • PonosetcDM © (17.06.10 12:50) [14]
    чтобы обрабатывать приход сообщений от сервера...
    можно и в отдельном потоке тоже самое делать, суть от этого не поменяется...
  • Сергей М. © (17.06.10 12:59) [15]
    Клиент с сервером должен взаимодействовать по схеме "послал запрос - дождался и получил ответ на этот запрос"

    Не вижу чтобы твой сервер в обработчике OnExecute посылал ответы клиенту на его запросы, хотя он обязан делать это именно там и нигде иначе.
  • PonosetcDM © (17.06.10 15:15) [16]
    Интересно, а если у меня на сервере произошло какое, то изменение, и я хачу сообщить об этом клиенту, чмне что прикажешь ждать, пока клиент не спросит у сервера, типа "все ли у тя в порядке?"... это же не прально...
    я бы хател сам уведомлять подключившихся клиентов о том что у мя что-то не так...чего я не магу сделать в OnExecute => должен быть способ это сделать...))
  • Сергей М. © (17.06.10 15:28) [17]

    > чего я не магу сделать в OnExecute


    Сделать это в OnExecute тебе запрещает религия ?


    > а если у меня на сервере произошло какое, то изменение,
    > и я хачу сообщить об этом клиенту, чмне что прикажешь ждать,
    >  пока клиент не спросит у сервера, типа "все ли у тя в порядке?
    > "


    1. К. делает запрос "Сервер, я жду изменений"
    2. С. отвечает на запрос "Нет изменений".
    3. goto 1

    или

    1. К. делает запрос "Сервер, я жду изменений"
    2. С. отвечает на запрос "На тебе изменеия".
    3. К. получает и обрабатывает изменения .
    4. goto 1

    Именно по этим сценариям ты взаимодейстуешь прямо сейчас с delphimaster.ru-сервером и нос почему-то не воротишь)
  • PonosetcDM © (17.06.10 15:37) [18]
    Хорошо, пример такой: на сервере ясмотрю картинки, а на клиенте хачу чтобы мне приходило имя файла этой картинки....
    Исходя из [17] выходит, что клиент должен постоянно опрашивать сервер, и получать от него это имя файла, и когда будет просматриваться другая картинка, я и получу это "другое" имя файла...

    Но ведь по моему логичнее было бы просто при открытии очередной картинки сервером, посылать имя файла этой "другой" картинки клиенту...
  • Сергей М. © (17.06.10 15:47) [19]

    > клиент должен постоянно опрашивать сервер


    Для подавляющего большинства распределенных приложений это абсолютно нормальная и вполне оправданная логика.
  • PonosetcDM © (17.06.10 15:50) [20]
    А как же быть с тем меньшинством???? Для которых эта "абсолютно нормальная логика" не одходит. Я не говорю, что мой проэкт не подходит под поняти "подавляющее большинство распределённых приложений", но просто интересно как быть...??
  • Сергей М. © (17.06.10 15:53) [21]
    Протокол инф.обмена должен соответствовать этой логике "меньшинства".
    Ну и, разумеется, реализация этого протокола должна быть соответствующей.
  • Anatoly Podgoretsky © (17.06.10 15:56) [22]
    > PonosetcDM  (17.06.2010 15:15:16)  [16]

    А ты сервер или спамер. Но ты имеешь право посылать сообщения
    подсоединившимся к тебе пользователям, если они готовы слушать тебя.
  • Anatoly Podgoretsky © (17.06.10 15:58) [23]
    > PonosetcDM  (17.06.2010 15:37:18)  [18]

    Постоянно опрашивать не надо, а надо ждать сообщения от сервера, как
    поступит так и обрабатывай. После установки соединения между сервером и
    клиентом нет разницы, они равноправны. Смотри методы и свойства TIdTCPServer
    и твоего клиента.
  • PonosetcDM © (17.06.10 16:24) [24]
    Anatoly Podgoretsky ©   (17.06.10 15:58) [23]
    Я не знаю прочитали  вы полностью нашу с Сергеем переписку или нет, пэтому уточню суть проблеммы:
    Есть приложение с TIdTCPServer(сервер) и приложение с TIdTCPClient(клиент).
    1. я делаю клиентом коннект к серверу   IdTCPClient1.Connect;
      все хорошо, все подлючается, все работает.
    2. я отправляю сообщение клиентом, серверу, он(сервер) обрабатывает его.
      все хорошо, все принято и обработано, все работает.
    3. я посылаю сообщение сервером, клиенту, он(клиент) обрабатывает его.
      все хорошо, все принято и обработано, все работает.

    Шаги 2 и 3 выполнять можно скока ХОШЬ....

    4. делаю клиентом дисконнект. все дисконнектится все нормально...
    5. делаю коннект, а вот тут "пффууук...." клиент грит, что он подконнектился, а сервер не реагирует, и ри попытке отправить сервером сообщение клиенту происходит "Connection Closed Grasfully"..., а при попытке повторного коннекта(без Disconnect), клиент говорит Already connected.. т.е. он считает, что он уже подключен...
  • Anatoly Podgoretsky © (17.06.10 16:30) [25]
    > PonosetcDM  (17.06.2010 16:24:24)  [24]

    Я как раз прочитал и ответил.
    После коннекта установлены двухсторонние отношения и клиент и сервер
    равноправны. Опрашивать ничего не надо, надо ждать сообщения в отдельном
    потоке конечно с использованием WaitForSingleObject
  • Сергей М. © (17.06.10 16:30) [26]

    > PonosetcDM ©   (17.06.10 16:24) [24]


    Ты так и не объяснил какая религия и почему запрещает тебе передавать данные клиенту непосредственнов в OnExecute
  • Anatoly Podgoretsky © (17.06.10 16:31) [27]
    > PonosetcDM  (17.06.2010 16:24:24)  [24]

    В ICS и это делать не надо, достаточно написать обработчик OnReceive, поток
    нужен для Инди. Но это моменты реализации.
  • PonosetcDM © (18.06.10 08:53) [28]
    Воооо.... ваще чума....
    я запустил программу(сервер)
    подключился к ней по telnet из cmd,
    сервак послал клиенту сообщение, все окей,
    принято telnet'ом, обработано...
    закрываю telnet,
    открываю telnet,
    делаю коннект "типа все окей", сервак шлет сообщение клиенту и.......
     правильно  "Connection Closed Grasfully"... ваще жуть...
  • Сергей М. © (18.06.10 09:28) [29]

    > ваще чума


    > ваще жуть


    А скажи, любезный, вот ты заблокировал список Contexts, а разблокировать его за тебя кто будет, Пушкин ?

    Ведь не ты один этим списком пользуешься - им еще и TIdCustomTCPServer пользуется, причем в 1-ю очередь !

    При обработке событий коннекта/дисконнекта IdCustomTCPServer обращается к этому списку, выполняя попытку заблокировать его для внесения соотв.изменения, например, для удаления Item[0] после дисконнекта 1-го клиента и вновь создания Item[0] при коннекте ..

    А ты взял и уселся на него верхом, не пуская никого покататься)

    Вот тебе и грабли)
  • Slym © (18.06.10 10:02) [30]
    1. протокол - говно
    ты где видал что сначала идет список длинн, потом список данных
    (табличное представление не в счет)
    общепринято: длинна-значание, длинна-значение

    2. описание структур - говно, дублирующие поля totalSize и ParamsLength в итоге потенциальное переполнение буфера когда totalSize<>Sum(ParamsLength)

    3. работа с памятью - говно (cp := 2 + SizeOf(cardinal) + tmsg.fHeader.ParamCount * Sizeof(cardinal);)

    4. работа с потоками - говно, общение с VCL в потоке (Memo1.Lines.Add)

    это только про сервер...
    про клиента:
    таймер убил меня, читать дальше нет мочи
  • Slym © (18.06.10 10:30) [31]
    вот сравни с [3]
    procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
    var
     tmsg : TPackage;
     i: byte;
     recvfs: TFileStream;
     MemoLines:string;
    begin
     with AContext.Connection.Socket,tmsg.fHeader,tmsg.fData do
     begin
       //начинаем жуткое месиво текстовых (ReadLn) и бинарных (ReadByte) операций
       totalSize :=StrToInt64(ReadLn);//нигде не использую т.к. нафиг надо...
       cmd:=ReadByte;
       ParamCount := ReadByte;

       SetLength(ParamsLength,ParamCount);
       for i:=0 to ParamCount-1 do
         ParamsLength[i]:=ReadLongInt(false);

       SetLength(Params,ParamCount);
       for i:=0 to ParamCount-1 do
         Params[i]:=ReadString(ParamsLength[i],enDefault);

       MemoLines:='';
       MemoLines:=MemoLines+'*********** We have a new message*******'+#13#10;
       MemoLines:=MemoLines+'   Message CMD Code = '+ IntToStr(tmsg.fHeader.cmd)+#13#10;
       MemoLines:=MemoLines+'   Message Params: '+#13#10;
       for i:=0 to ParamCount-1 do
         MemoLines:=MemoLines+'      ' + (Params[i])+#13#10;

       Case cmd of
         1 :  MemoLines:=MemoLines+'We have a new connection...'+#13#10;
         2 :  MemoLines:=MemoLines+'This is a message'+#13#10;
         3 :  begin
                recvfs:= TFileStream.Create(ExtractFileName(Params[0])+'.tmp',fmCreate);
                try
                   ReadStream(recvfs,StrToInt(Params[1]),false);
                finally
                   recvfs.Free;
                end;
                   MemoLines:=MemoLines+'-----> New File upload complete...'+#13#10;
              end;
       end;
     end;
     MemoLines:=MemoLines+'*********** End of new message*******'+#13#10;

     //ПОТОКОБЕЗОПАСНО_ПЕРЕДАЕМ(MemoLines,в Memo1.Lines);
    end;

  • Anatoly Podgoretsky © (18.06.10 10:31) [32]

    > делаю коннект "типа все окей", сервак шлет сообщение клиенту
    > и.......
    >  правильно  "Connection Closed Grasfully"... ваще жуть..
    > .

    Претензии к реализации сервера, невероятно кривая.
  • Сергей М. © (18.06.10 10:34) [33]

    > Anatoly Podgoretsky ©   (18.06.10 10:31) [32]


    Какая бы ни была кривая, но UnlockList-то надо вызывать)
  • Slym © (18.06.10 10:54) [34]
    procedure TForm1.SendPackage(pcmd, pparamCount: byte;
    pparams: array of string);
    var
     tmsg:TPackage;
     buf:TMemoryStream;
     List:TList;
     i:integer;
    begin
     buf:=TMemoryStream.Create;
     try
       //формирование TPackage можно нафик выкинуть
       with tmsg.fHeader,tmsg.fData do
       begin
         cmd:= pcmd;
         ParamCount := pparamCount;
         SetLength(ParamsLength,ParamCount);
         SetLength(Params,ParamCount);
         for i:=0 to ParamCount-1 do
         begin
           Params[i]:=pparams[i];
           ParamsLength[i]:=length(Params[i]);
         end;

         buf.WriteBuffer(cmd,SizeOf(cmd));
         buf.WriteBuffer(ParamCount,SizeOf(ParamCount));
         for i:=0 to ParamCount-1 do
           buf.WriteBuffer(ParamsLength[i],SizeOf(cardinal));
         for i:=0 to ParamCount-1 do
           buf.WriteBuffer(PChar(Params[i])^,ParamsLength[i]);
       end;

       //шо за нах!Items[0]! пошлем всех!
       List:=IdTCPServer1.Contexts.LockList;
       try
         for i:=0 to List.Count-1 do
         with TIdContext(List.Items[i]).Connection.Socket do
         begin
           WriteLn(IntToStr(buf.Size));
           Write(buf);
         end;
       finally
         IdTCPServer1.Contexts.UnlockList;//ОБЯЗАТЕЛЬНО!!!
       end;
     finally
       buf.Free;//ОБЯЗАТЕЛЬНО!!!
     end;
    end;

  • Slym © (18.06.10 11:16) [35]
    ЗАБЫЛ добавить:
    как только выходим из IdTCPServer1Execute - финиталякомедия конекшен рвется, так что переделывай в все в одном IdTCPServer1Execute или как то усыпляй IdTCPServer1Execute...
  • Anatoly Podgoretsky © (18.06.10 11:18) [36]
    > Сергей М.  (18.06.2010 10:34:33)  [33]

    Это часть кривизны.
  • PonosetcDM © (18.06.10 11:48) [37]
    Блин я согласен все замечания хороши, базара ноль... да вот проблемма остается актуальной..
    на форме компоненты TIdTCPServer, TMemo и ТБатон
    вот код куда уж проще то...

    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdContext,
     StdCtrls, Buttons;

    type
     TForm1 = class(TForm)
       IdTCPServer1: TIdTCPServer;
       Memo1: TMemo;
       BitBtn1: TBitBtn;
       procedure IdTCPServer1Execute(AContext: TIdContext);
       procedure FormCreate(Sender: TObject);
       procedure FormDestroy(Sender: TObject);
       procedure BitBtn1Click(Sender: TObject);
       procedure IdTCPServer1Connect(AContext: TIdContext);
       procedure IdTCPServer1Disconnect(AContext: TIdContext);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
    var s:string;
    begin
     s:=AContext.Connection.IOHandler.ReadLn;
     Memo1.Lines.Add(s);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     IdTCPServer1.Active:=true;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
     IdTCPServer1.Active:=false;
    end;

    procedure TForm1.BitBtn1Click(Sender: TObject);
    var i:integer;
    begin
      try
        for i:=0 to IdTCPServer1.Contexts.LockList.Count-1 do
        with TIdContext(IdTCPServer1.Contexts.LockList.Items[i]).Connection.Socket do
          WriteLn('123');
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;

    procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
    begin
     Memo1.Lines.Add('we have a new connection')
    end;

    procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
    begin
     Memo1.Lines.Add('Client disconnected');
    end;

    end.

    иииииииии............ все теже грабли...

    Запускаю эту прогу,
    запускаю телнет
    коннект телнета "o localhost 12312"
    нажимаю на батон, в окне телнета появляется "123",
    нажимаю на батон ищё раз, в окне телнета появляется ищё "123",
    закрываю телнет, срабатывает дисконнект
    запускаю телнет опять, прога при этом не перезапускалась(естественно)...
    делаю телнетом "o localhost 12312", и даже коннект у сервера не срабатывает....
    все по шагам разжевал....
  • Сергей М. © (18.06.10 11:57) [38]

    > все теже грабли


    Ну где-же "теже" ?
    Connection closed gracefully как рукой сняло)

    И, кстати, ты в [35] вник ?
  • PonosetcDM © (18.06.10 12:04) [39]
    Нууу не знаю что у Вас сняло, у мя как было так и осталось, какая у Вас версия Indy????

    Про [35] хзхз, почиму это коннекшен рвется????

    и что за усыпляй???

    у мя когда клиент коннект сделал, заходит в и
    IdTCPServer1Execute(AContext: TIdContext);
    останавливается на AContext.Connection.IOHandler.ReadLn,
    пока не придет что-ть.
  • Anatoly Podgoretsky © (18.06.10 12:26) [40]
    > PonosetcDM  (18.06.2010 11:48:37)  [37]

    Это же потоки, откуда Memo1.Lines.Add без синхронизации.
  • Сергей М. © (18.06.10 12:44) [41]

    > почиму это коннекшен рвется?


    Потому что как только клиент отправит какую-либо строку, ReadLn тут же вернет управление, и после лажи [40] Execute завершит выполнение, что ведет к разрыву соединения по инициативе сервера
  • PonosetcDM © (18.06.10 12:48) [42]

    > Это же потоки, откуда Memo1.Lines.Add без синхронизации.


    Окей, давай эту строчку ваще уберём.... и все равно
    T = Telnet
    S = Server Project

    запустил Т
    запустил S
    T, o localhost 12312
    S принял подключение
    S отправил "123", T обработал и выдал "123"
    T закрыли, Т открыли
    T, o localhost 12312
    S при посылке грит Connection closed gracefully

    теперь ваще все Гут должно быть, никакой проблеммы с синхронизацией...
    и все тоже самое...
  • Сергей М. © (18.06.10 12:51) [43]

    > PonosetcDM ©   (18.06.10 12:48) [42]



    > запускаю телнет опять,
    > делаю телнетом "o localhost 12312", и даже коннект у сервера
    > не срабатывае


    Зачем же давить BitBtn1, если нет ни одного коннекта ?)
  • PonosetcDM © (18.06.10 13:13) [44]
    Хм.... ТОгда вопрос: А почиму его нет))????? Ведь когда телнет дисконектился, у сервера сработал дисконнект, а потом коннект не срабатывает...
  • Slym © (18.06.10 14:09) [45]
    PonosetcDM ©   (18.06.10 11:48) [37]
    for i:=0 to IdTCPServer1.Contexts.LockList.Count-1 do

    чтож ты делаешь то? нехороший человек
  • Slym © (18.06.10 14:11) [46]
    procedure TForm1.BitBtn1Click(Sender: TObject);
    var i:integer;
    list:TList;
    begin
     list:=IdTCPServer1.Contexts.LockList;
     try
       for i:=0 to list.Count-1 do
       with TIdContext(list.Items[i]).Connection.Socket do
         WriteLn('123');
     finally
       IdTCPServer1.Contexts.UnlockList;
     end;
    end;
  • Slym © (18.06.10 14:13) [47]
    Сергей М. ©   (18.06.10 12:44) [41]
    +1 к [35]
  • PonosetcDM © (18.06.10 14:39) [48]
    Мдааа......... вот так таааааакккк...... Спс большое вроде бы все работает, теперь буду следить за всем, и закреплю в аналах своей памяти все посты сказанные сдесь...

    Только хотелось бы узнать по-подробнее: почиму не работает с for i:=0 to IdTCPServer1.Contexts.LockList.Count-1 do,
    а если IdTCPServer1.Contexts.LockList.Count-1 переопределить, то все работает??

    СПС всем огромное...
  • PonosetcDM © (18.06.10 14:40) [49]
    сдесь = здесь
  • Сергей М. © (18.06.10 20:30) [50]

    > в аналах своей памяти


    Анальная у тебя память, однако))))
  • Slym © (20.06.10 13:05) [51]
    PonosetcDM ©   (18.06.10 14:39) [48]
    количество LockList дожно быть равно колву UnlockList
    тут
    PonosetcDM ©   (18.06.10 11:48) [37]
    procedure TForm1.BitBtn1Click(Sender: TObject);
    var i:integer;
    begin
     try
       for i:=0 to IdTCPServer1.Contexts.LockList.Count-1 do
       with TIdContext(IdTCPServer1.Contexts.LockList.Items[i]).Connection.Socket do
         WriteLn('123');
     finally
       IdTCPServer1.Contexts.UnlockList;
     end;
    end;


    Колво LockList = 1+ListCount
    и это при условии что дельфи за тебя оптимизирует i:=0 to IdTCPServer1.Contexts.LockList.Count-1 за менив постоянное вычисление предела цикла на единичное вычисление

    колво UnlockList = 1
  • Anatoly Podgoretsky © (20.06.10 13:19) [52]
    > Slym  (20.06.2010 13:05:51)  [51]

    А ты можешь документально подтвердить постоянное вычисление предела цикла?
  • Сергей М. © (20.06.10 22:30) [53]

    > Slym ©   (20.06.10 13:05) [51]
    > количество LockList дожно быть равно колву UnlockList


    Это же не семафор)
  • Slym © (21.06.10 06:04) [54]
    Сергей М. ©   (20.06.10 22:30) [53]
    а критической секции это не касается?
    один поток накрутит EnterCriticalSection и пока не скрутит столько же раз Leave - другие будут ждать
    Anatoly Podgoretsky ©   (20.06.10 13:19) [52]
    читать отрывочно умеешь, теперь прочитай еще раз полностью: вникни в формулу (1 (вычисление предела)+ListCount (кол-во итераций)) и дочитай про оптимизацию
  • Коля (03.09.14 21:51) [55]
    ТЫ локлист открыл и заблокировал,разблокируй его и все пойдет
 
Конференция "Сети" » Проблемма TIdTCPServer [D7, WinXP]
Есть новые Нет новых   [118642   +47][b:0.001][p:0.004]