Конференция "Сети" » Проблемма 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]

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


    Для подавляющего большинства распределенных приложений это абсолютно нормальная и вполне оправданная логика.
 
Конференция "Сети" » Проблемма TIdTCPServer [D7, WinXP]
Есть новые Нет новых   [134427   +35][b:0][p:0.001]