Форум: "Сети";
Текущий архив: 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