Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2011.04.24;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.54 MB
Время: 0.004 c
1-1252579314
webpauk
2009-09-10 14:41
2011.04.24
тень


15-1294819013
KSergey
2011-01-12 10:56
2011.04.24
Синхронизация файлов по FTP


15-1294650746
Palladin
2011-01-10 12:12
2011.04.24
Автоскролл при нажатии на колесо мыши


15-1294694994
Юрий
2011-01-11 00:29
2011.04.24
С днем рождения ! 11 января 2011 вторник


15-1294834077
George
2011-01-12 15:07
2011.04.24
TIdHTTP.Get и Windows 7





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский