Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.04.24;
Скачать: CL | DM;

Вниз

Переподключится к другому телнет серверу   Найти похожие ветки 

 
Alex_C   (2009-03-10 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


 
Сергей М. ©   (2009-03-11 08:33) [1]

1. Замени

TelnetSocket.Close;

на

Socket.Close;

2. Убери из обработчика OnError непосредственный вызов FindNextTelnetServer
Вместо этого посылай окну формы любое предопределенное асинхронное сообщение, в обработчике которого собссно и вызывай FindNextTelnetServer


 
Alex_C   (2009-03-11 09:40) [2]

Спасибо за совет. Заменил на SocetClose.
Заменил в ClientOnError прямой вызов FindNextTelnetServer
на PostMessage, с последущим вызовом в обработке этого сообщения FindNextTelnetServer. Однако ничего не изменилось...


 
Сергей М. ©   (2009-03-11 09:43) [3]

Т.е. все попытки подключения приводят к отказу с кодом 10049 ?


 
Alex_C   (2009-03-11 10:10) [4]

Да, а вот ставишь первым работающий сервер - прекрасно соединяется.
Причем что заметил:
для проверки делаешь список адресов серверов:
не работающий
работающий
не работающий
и т.д.
При обращении к нерабочему адресу как положено несколько секунд его опрашивает, потом выдает Lookup Error (что верно), а при обращении к точно рабочему - прям сразу выкидывает 10049, и т.д.


 
Alex_C   (2009-03-11 10:43) [5]

Сейчас попробовал:
а если сделать так:
не работающий сервер
работающий
работающий

то первый работающий сервер выдает ошибку 10049, а второй подсоединяется нормально, даже если это один и тот же сервер.


 
Сергей М. ©   (2009-03-11 10:54) [6]


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


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


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

А под "нерабочим адресом", насколько я понял, ты подразумеваешь IP-адрес хоста, недоступного по каким-то причинам на момент обращения к нему.


 
Сергей М. ©   (2009-03-11 10:57) [7]


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


Это как ?

Давай уже приводи список в том виде, в котором данные из него при каждой итерации попадают в св-ва Host и Port компонента непосредственно перед тем как он переводится тобой в состояние Active=True ..


 
Alex_C   (2009-03-11 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, снова нажимаю эту же кнопку - соединение есть! Т.е. такое впечатление что при неудачной попытке ошибка не сбрасывается, а сбрасывается только при обращении к существующему адресу.


 
Сергей М. ©   (2009-03-11 13:00) [9]


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


Может все же не адрес сервера, а имя хоста ?


 
Alex_C   (2009-03-11 13:47) [10]

ну имелось ввиду именно имя хоста.
да и еслиб что то не верно было, он бы вообще не соединял...


 
Сергей М. ©   (2009-03-11 14:20) [11]


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


Тогда что есть "нерабочий адрес", если в твоем списке не адреса, а имена хостов ?


 
Alex_C   (2009-03-11 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   (2009-03-11 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;


Т.е. перед повторным использованием нужно уничтожать и снова создвать...
Не уверен, что это верно..


 
Сергей М. ©   (2009-03-11 15:33) [14]

при Lookup-отказе не выполняй Socket.Close

Ситуация изменилась ?


 
Alex_C   (2009-03-11 15:48) [15]

Убрал Socket.Close везде вообще...
Нет, ничего не изменилось.
Блин! Все перепробовал!
Замкнутый круг какой то....
Но ведь обычный виндовый telnet все нормально отрабарывает....


 
Сергей М. ©   (2009-03-11 17:23) [16]

Мда .. это засада..

завтра подскажу как выкрутиться


 
FireMan_Alexey ©   (2009-03-12 09:16) [17]

Попробуй при дисконнекте или ошибке отсылать сообщение постом и делать ФРИ для твоего TelnetSocket, а при новом коннекте заново КРЕАТИТЬ :)))
Думаю в твоем случае это подойдет!!!
Конечно можно переписать на сокетах, тогда таких глюков не будет.
Тем более что тебе для эмитации телнета не блок режим не обязателен...


 
Сергей М. ©   (2009-03-12 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   (2009-03-12 10:15) [19]

То Сергей М.: Приветствую! Не получилось - в строке

if sa.sin_addr.S_addr = INADDR_ANY then

sa.sin_addr.S_addr не равен INADDR_ANY...


 
Alex_C   (2009-03-12 10:18) [20]

В общем интересная вещь получается: адрес определяется! Т.е. как бы все верно, но соединения не происходит. Мда. Вроде все просто, ан нет...


 
Сергей М. ©   (2009-03-12 10:19) [21]

А чему равен ?


 
Alex_C   (2009-03-12 10:47) [22]

У меня получается 1244580 - я так понимаю это и есть представление адреса?


 
Сергей М. ©   (2009-03-12 12:17) [23]


type
 TConnectState = (csNone, csSuccess, csFail, csNeedReconnect);

var
 ConnectState: TConnectState;
 ErrCode: Integer;

procedure TForm1.Button3Click(Sender: TObject);
var
 sl: TStrings;
 i: Integer;
 NextHost, NextService: String;
begin
 sl := TStringList.Create;
 try
   sl.Add("first_notexistinghostname:telnet"); //хост с таким именем заведомо не существует
   sl.Add("rambler.ru:telnet"); //хост с таким именем заведомо существует и доступен, но телнет-сервис на нем не активен или не доступен
   sl.Add("rn6bn.73.ru:telnet"); //хост с таким именем заведомо существует и доступен, телнет-сервис на нем заведомо активен и доступен
   sl.Add("second_notexistinghostname:telnet"); //хост с таким именем заведомо не существует
   sl.Add("rn6bn.73.ru:telnet"); //хост с таким именем заведомо существует и доступен, телнет-сервис на нем заведомо активен и доступен
   i := 0;
   while i < sl.Count do begin
     ConnectState := csNone;
     NextHost := Copy(sl[i], 1, Pos(":", sl[i])-1);
     NextService := Copy(sl[i], Pos(":", sl[i])+1, Length(sl[i]));
     ClientSocket.Host := NextHost;
     ClientSocket.Service := NextService;
     Memo.Lines.Add("--- " + IntToStr(i) + ". Попытка коннекта к " + sl[i] + " ...");
     ClientSocket.Active := True;
     while ConnectState = csNone do begin
       Application.ProcessMessages;
       Sleep(0);
     end;
     case ConnectState of
       csSuccess:
         begin
           Memo.Lines.Add("Успешное подключение к " + sl[i]);
           ClientSocket.Active := False;
           Inc(i);
         end;
       csFail:
         begin
           Memo.Lines.Add("Отказ при подключении к " + sl[i] + ", код отказа: " + IntToStr(ErrCode));
           Inc(i);
         end;
       csNeedReconnect:
         begin
           Memo.Lines.Add("Отказ при подключении к " + sl[i] + ", код отказа: " + IntToStr(ErrCode) + ", требуется повторная попытка");
         end;
     end;
   end;
 finally
   sl.Free;
 end;
end;

procedure TForm1.ClientSocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
 ConnectState := csFail;
 ErrCode := ErrorCode;
 if (ErrorEvent = eeConnect) and (ErrorCode = WSAEADDRNOTAVAIL) then
 begin
     ConnectState := csNeedReconnect;
 end;
 ErrorCode := 0;
 Socket.Close;
end;

procedure TForm1.ClientSocketConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
 ConnectState := csSuccess;
end;


 
Alex_C   (2009-03-12 14:57) [24]

То Сергей М. : Огромноге спасибо! В очередной раз Вы мне помогли!
Правда так до конца не понятно, почему ж он как надо не работает - но по ходу тут надо самому писать свой ClientSocket - и тут уже разбираться!
Еще раз спасибо!


 
Сергей М. ©   (2009-03-12 15:31) [25]


> не понятно, почему ж он как надо не работает


Похоже на баг - LookupState после отказа с кодом 11001 не возвращается в состояние lsIdle.

Можно было бы  сделать это и вручную прямо в обработчике OnError, но св-во это - read only


 
Сергей М. ©   (2009-03-12 15:47) [26]

Можно поступить и так - непосредственно перед очередной попыткой коннекта к какому либо хосту читать св-во ClientSocket.Socket.LookupState, и если оно не равно lsIdle, то разрушить компонент и тут же создать его вновь.


 
_0   (2009-03-12 18:43) [27]

asConnect убери из ClientSocket.Socket.AsyncStyles


 
Сергей М. ©   (2009-03-12 19:40) [28]


> _0   (12.03.09 18:43) [27]


Ахинея.


 
FireMan_Alexey ©   (2009-03-12 20:01) [29]

Есть очень старый(в смысле давно писал) переписанный КлиентСокет, могу кинуть :)



Страницы: 1 вся ветка

Текущий архив: 2011.04.24;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.013 c
2-1295517155
Alex_C
2011-01-20 12:52
2011.04.24
Как в метафаил скопировать битмап?


15-1294859352
Внук
2011-01-12 22:09
2011.04.24
Исправления в DOA


15-1294926003
12
2011-01-13 16:40
2011.04.24
EhLib v3.6. Нормально работает?


2-1295432083
Scott Storch
2011-01-19 13:14
2011.04.24
упростить алгоритм TStrings.SetDelimiterText


15-1293095836
Павел Калугин
2010-12-23 12:17
2011.04.24
Встретим новый год в Нижнем Новгороде?