Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Переподключится к другому телнет серверу [D7, WinXP]


Страницы:   1 2

Alex_C ©   (2009-03-10 20:20:00) 

Проблема: получаю данные по телнет протоколу из инета:
Сделал:

 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


FireMan_Alexey   (2009-03-12 20:01:00) [1]

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


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


> _0   (12.03.09 18:43) [27]


Ахинея.


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

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


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

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


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


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


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

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


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

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


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


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 10:47:00) [8]

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


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

А чему равен ?


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

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


Alex_C   (2009-03-12 10:15:00) [11]

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

if sa.sin_addr.S_addr = INADDR_ANY then

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


Сергей М.   (2009-03-12 09:19:00) [12]

Вот один из наиболее простых вариантов преодоления засады:

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;


FireMan_Alexey   (2009-03-12 09:16:00) [13]

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


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

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

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


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

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


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

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

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


Alex_C   (2009-03-11 15:00:00) [17]

однако все заработало, если сделать так:


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;


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


Alex_C   (2009-03-11 14:41:00) [18]

В общем привожу полный код тестовой программы.
Форма - на ней 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 - произойдет соединение.


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


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


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


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

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо