![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Переподключится к другому телнет серверу [D7, WinXP]
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]ну имелось ввиду именно имя хоста.
да и еслиб что то не верно было, он бы вообще не соединял...