Конференция "Сети" » Переподключится к другому телнет серверу [D7, WinXP]
 
  • Alex_C (10.03.09 20:20) [0]
    Проблема: получаю данные по телнет протоколу из инета:
    Сделал:

     TelnetSocket: TClientSocket;

    ...
    procedure TTelnetForm.ClientOnError(Sender: TObject; Socket: TCustomWinSocket;
     ErrorEvent: TErrorEvent; var ErrorCode: integer);
    var
     ErrStr: string;
    begin
     case ErrorEvent of
       eeGeneral: ErrStr := 'General Error';
       eeSend: ErrStr    := 'Send Error';
       eeReceive: ErrStr := 'Receive Error';
       eeConnect: ErrStr := 'Connect Error';
       eeDisconnect: ErrStr := 'Disconnect Error';
       eeAccept: ErrStr  := 'Accept Error';
       eeLookup: ErrStr  := 'Lookup Error';
     end;

     SetLength(TelnetText, Length(TelnetText) +  1);
     TelnetText[Length(TelnetText)-1] := 'Error Type : ' + ErrStr +
       ', Error Code : ' + IntToStr(ErrorCode);
     ErrorCode := 0;
     TelnetSocket.Close;
     // Подключаемся к следущему в списке серверов при ошибке
     FindNextTelnetServer;
    end;

    ...

    procedure TTelnetForm.FindNextTelnetServer;
    begin
    // Пока не пончится таблица адресов - перебираем адреса
     if (not TelnetTable.Eof) and (TelnetTable.FindNext) then
     begin
       TelnetSocket.Host   := TelnetTableAddress.AsString;
       TelnetSocket.Port   := TelnetTablePort.Value;
       TelnetSocket.Active := True;
     end
     else
     begin
       SetLength(TelnetText, Length(TelnetText) +  1);
       TelnetText[Length(TelnetText)-1] := 'Can not find working server!';
       CopyTelnetStrToTelnetWindows;

       if TelnetSocket.Active then
         TelnetSocket.Close;
     end;
    end;



    Проблема заключается в том, что если первый сервер в списке недоступен, он и к остальным поключится не может.
    Пишет
    Error Type : Connect Error, Error Code : 10049
  • Сергей М. © (11.03.09 08:33) [1]
    1. Замени

    TelnetSocket.Close;


    на

    Socket.Close;



    2. Убери из обработчика OnError непосредственный вызов FindNextTelnetServer
    Вместо этого посылай окну формы любое предопределенное асинхронное сообщение, в обработчике которого собссно и вызывай FindNextTelnetServer
  • Alex_C (11.03.09 09:40) [2]
    Спасибо за совет. Заменил на SocetClose.
    Заменил в ClientOnError прямой вызов FindNextTelnetServer
    на PostMessage, с последущим вызовом в обработке этого сообщения FindNextTelnetServer. Однако ничего не изменилось...
  • Сергей М. © (11.03.09 09:43) [3]
    Т.е. все попытки подключения приводят к отказу с кодом 10049 ?
  • Alex_C (11.03.09 10:10) [4]
    Да, а вот ставишь первым работающий сервер - прекрасно соединяется.
    Причем что заметил:
    для проверки делаешь список адресов серверов:
    не работающий
    работающий
    не работающий
    и т.д.
    При обращении к нерабочему адресу как положено несколько секунд его опрашивает, потом выдает Lookup Error (что верно), а при обращении к точно рабочему - прям сразу выкидывает 10049, и т.д.
  • Alex_C (11.03.09 10:43) [5]
    Сейчас попробовал:
    а если сделать так:
    не работающий сервер
    работающий
    работающий

    то первый работающий сервер выдает ошибку 10049, а второй подсоединяется нормально, даже если это один и тот же сервер.
  • Сергей М. © (11.03.09 10:54) [6]

    > к нерабочему адресу


    > выдает Lookup Error (что верно)


    Да вот как раз и не верно.
    Lookup Error - ошибка, возникающая не при недоступности хоста, а при невозможности разрешить имя хоста в его адрес.

    А под "нерабочим адресом", насколько я понял, ты подразумеваешь IP-адрес хоста, недоступного по каким-то причинам на момент обращения к нему.
  • Сергей М. © (11.03.09 10:57) [7]

    > даже если это один и тот же сервер


    Это как ?

    Давай уже приводи список в том виде, в котором данные из него при каждой итерации попадают в св-ва Host и Port компонента непосредственно перед тем как он переводится тобой в состояние Active=True ..
  • Alex_C (11.03.09 12:52) [8]
    То Сергей М. Для проверки набиваю любой несуществующий адрес.
    От правильно ругается - Lookup error - он его не находит.
    Так вот если сразу после этого, хоть в ручную, по нажантю на кнопку, хоть при вызове PostMessage из ф-ции ClientOnError при соединении с существующим адресом 1-й раз он напишет 10049 ошибку, второй раз - соединиться.
    Для проверки делал очень просто:
    создал для пробы 3 кнопки с такого вида кодом


      if TelnetSocket.Active then
        TelnetSocket.Socket.Close;
      TelnetSocket.Host   := <здесь в каждой кнопке пишу адрес сервера>;
      TelnetSocket.Port   := 23;
      TelnetSocket.Active := True;



    Первая - с несуществующим адресом, 2 другие - с существующим.
    Если нажимаю на существующий адрес - соединение есть. Не существующий - Lookup error, опять существующий - ошибка 10049, снова нажимаю эту же кнопку - соединение есть! Т.е. такое впечатление что при неудачной попытке ошибка не сбрасывается, а сбрасывается только при обращении к существующему адресу.
  • Сергей М. © (11.03.09 13:00) [9]

    > <здесь в каждой кнопке пишу адрес сервера>


    Может все же не адрес сервера, а имя хоста ?
  • Alex_C (11.03.09 13:47) [10]
    ну имелось ввиду именно имя хоста.
    да и еслиб что то не верно было, он бы вообще не соединял...
  • Сергей М. © (11.03.09 14:20) [11]

    > имелось ввиду именно имя хоста


    Тогда что есть "нерабочий адрес", если в твоем списке не адреса, а имена хостов ?
  • Alex_C (11.03.09 14:41) [12]
    В общем привожу полный код тестовой программы.
    Форма - на ней 2 кнопки и мемо.
    Button1 - с несуществующим адресом, Button2 - с работающим.


    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls, ScktComp;

    type
     TForm1 = class(TForm)
       Button1: TButton;
       Button2: TButton;
       Memo1: TMemo;
       procedure FormCreate(Sender: TObject);
       procedure FormDestroy(Sender: TObject);
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);
     private
       procedure ClientOnConnected(Sender: TObject; Socket: TCustomWinSocket);
       procedure ClientOnConnecting(Sender: TObject;
         Socket: TCustomWinSocket);
       procedure ClientOnDisconnected(Sender: TObject;
         Socket: TCustomWinSocket);
       procedure ClientOnError(Sender: TObject; Socket: TCustomWinSocket;
         ErrorEvent: TErrorEvent; var ErrorCode: integer);
       procedure ClientOnRead(Sender: TObject; Socket: TCustomWinSocket);
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;
     TelnetSocket: TClientSocket;

    implementation

    {$R *.dfm}

    //on connecting to server process

    procedure TForm1.ClientOnConnecting(Sender: TObject; Socket: TCustomWinSocket);
    var
     S: string;
    begin
     if TelnetSocket.Host = '' then
       S := TelnetSocket.Address
     else
       S := TelnetSocket.Host;

     Memo1.Lines.Add('Connecting to server [' + S + ']');
    end;

    //on connected to server process

    procedure TForm1.ClientOnConnected(Sender: TObject; Socket: TCustomWinSocket);
    var
     Connectcall, S: string;
    begin
     if TelnetSocket.Host = '' then
       S := TelnetSocket.Address
     else
       S := TelnetSocket.Host;

     Memo1.Lines.Add('Server of connected : ' + S);

     TelnetSocket.Socket.SendText('RX4HX' + #10 + #13);
    end;

    //on disconnect from server

    procedure TForm1.ClientOnDisconnected(Sender: TObject; Socket: TCustomWinSocket);
    var
     S: string;
    begin
     if TelnetSocket.Host = '' then
       S := TelnetSocket.Address
     else
       S := TelnetSocket.Host;

     Memo1.Lines.Add('Disconnected from server [' + S + ']');
    end;

    //on read from socket

    procedure TForm1.ClientOnRead(Sender: TObject; Socket: TCustomWinSocket);
    begin
     Memo1.Lines.Add(Socket.ReceiveText);
    end;

    //on client error

    procedure TForm1.ClientOnError(Sender: TObject; Socket: TCustomWinSocket;
     ErrorEvent: TErrorEvent; var ErrorCode: integer);
    var
     ErrStr: string;
    begin
     case ErrorEvent of
       eeGeneral: ErrStr := 'General Error';
       eeSend: ErrStr    := 'Send Error';
       eeReceive: ErrStr := 'Receive Error';
       eeConnect: ErrStr := 'Connect Error';
       eeDisconnect: ErrStr := 'Disconnect Error';
       eeAccept: ErrStr  := 'Accept Error';
       eeLookup: ErrStr  := 'Lookup Error';
     end;

     Memo1.Lines.Add('Error Type : ' + ErrStr +
       ', Error Code : ' + IntToStr(ErrorCode));
     ErrorCode := 0;
     Socket.Close;
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     // Создаем сокет телнета
     TelnetSocket := TClientSocket.Create(Self);
     TelnetSocket.OnConnecting := ClientOnConnecting;
     TelnetSocket.OnConnect := ClientOnConnected;
     TelnetSocket.OnDisconnect := ClientOnDisconnected;
     TelnetSocket.OnRead := ClientOnRead;
     TelnetSocket.OnError := ClientOnError;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
     TelnetSocket.Free;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
       if TelnetSocket.Active then
         TelnetSocket.Socket.Close;

     TelnetSocket.Host   := '1yu1exy.org';
     TelnetSocket.Port   := 8000;
     TelnetSocket.Active := True;
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
       if TelnetSocket.Active then
         TelnetSocket.Socket.Close;

     TelnetSocket.Host   := 'rn6bn.73.ru';
     TelnetSocket.Port   := 23;
     TelnetSocket.Active := True;
    end;

    end.



    Нажмите на Button2 - произойдет соединение с сервером.
    Затем нажмите на Button1 - выдаст ошибку Lookup server.
    Нажмите опять на Button2 - видаст ошибку 100049
    и опять на Button2 - произойдет соединение.
  • Alex_C (11.03.09 15:00) [13]
    однако все заработало, если сделать так:


    procedure TForm1.Button2Click(Sender: TObject);
    begin
     if Assigned(TelnetSocket) then
     begin
       FormDestroy(nil);
       TelnetSocket := nil;
     end;

     FormCreate(nil);
     TelnetSocket.Host   := 'rn6bn.73.ru';
     TelnetSocket.Address := '';
     TelnetSocket.Port   := 23;
     TelnetSocket.Active := True;
    end;



    Т.е. перед повторным использованием нужно уничтожать и снова создвать...
    Не уверен, что это верно..
  • Сергей М. © (11.03.09 15:33) [14]
    при Lookup-отказе не выполняй Socket.Close

    Ситуация изменилась ?
  • Alex_C (11.03.09 15:48) [15]
    Убрал Socket.Close везде вообще...
    Нет, ничего не изменилось.
    Блин! Все перепробовал!
    Замкнутый круг какой то....
    Но ведь обычный виндовый telnet все нормально отрабарывает....
  • Сергей М. © (11.03.09 17:23) [16]
    Мда .. это засада..

    завтра подскажу как выкрутиться
  • FireMan_Alexey © (12.03.09 09:16) [17]
    Попробуй при дисконнекте или ошибке отсылать сообщение постом и делать ФРИ для твоего TelnetSocket, а при новом коннекте заново КРЕАТИТЬ :)))
    Думаю в твоем случае это подойдет!!!
    Конечно можно переписать на сокетах, тогда таких глюков не будет.
    Тем более что тебе для эмитации телнета не блок режим не обязателен...
  • Сергей М. © (12.03.09 09:19) [18]
    Вот один из наиболее простых вариантов преодоления засады:

    procedure TForm1.ClientOnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    var
     sa: TSockAddrIn;
     len: Integer;
    begin
    ...
     if (ErrorEvent = eeConnect) and (ErrorCode = WSAEADDRNOTAVAIL) then
     begin
       GetSockName(Socket.SocketHandle, sa, len);
       if sa.sin_addr.S_addr = INADDR_ANY then
         следует повторить попытку асинхронного коннекта к ЭТОМУ же хосту, теперь она не вызовет отказ с кодом 10049

     end;
    ...
    end;

  • Alex_C (12.03.09 10:15) [19]
    То Сергей М.: Приветствую! Не получилось - в строке

    if sa.sin_addr.S_addr = INADDR_ANY then


    sa.sin_addr.S_addr не равен INADDR_ANY...
 
Конференция "Сети" » Переподключится к другому телнет серверу [D7, WinXP]
Есть новые Нет новых   [134435   +33][b:0][p:0.004]