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

Вниз

странная проблема с сокетами:   Найти похожие ветки 

 
GroZ   (2004-05-20 11:53) [0]

Deiphi 5

Нужно с помощью клиент-сокетов конестится к нескольким серверам (на каждый сервер соответственно по клиент-сокету) т.е. есть массив клиент-сокетов. Пытаюсь сделать это следующим образом:

без переделок:
  for i := 0 to Length(PrmConns)-1 do begin
     if not PrmConns[i].ClientSocket.Active and not PrmConns[i].Connecting then begin
        PrmConns[i].ClientSocket.Close;
        PrmConns[i].Connecting := true;
        PrmConns[i].ClientSocket.Port := PrmConns[i].CurrPort;
        PrmConns[i].ClientSocket.Address := PrmConns[i].IP;
        PrmConns[i].ClientSocket.Open;

     end;
     if PrmConns[i].ClientSocket.Active and PrmConns[i].Connecting then begin
        PrmConns[i].Connecting := False;
     end;
  end;

Если сервер запущен, то всё хорошо работает ... но в противном случае (если сервер не запущен) через несколько часов работы Окна маразмятся ... что-то происходт с сетевым сервисом: перестаёт работать инет, не работает Outlook Express (не может приконнектится к серверу) правда по локалке на Sharing можно зайти ...
Выше приведённый код запускается в Timer-e, каждые 800 мс ..
Также в обработчике ошибки клиент-сокета (ClientSocket.OnError):

PrmConns[i].Connecting := False;
PrmConns[i].ClientSocket.Active := False;
PrmConns[i].CurrPort := PrmConns[i].CurrPort + 1;
if (PrmConns[i].CurrPort < PrmConns[i].Port.s) or (PrmConns[i].CurrPort > PrmConns[i].Port.e) then PrmConns[i].CurrPort := PrmConns[i].Port.s;
ErrorCode := 0;


Создаю клиент-сокет так:
procedure TMyClass.CreateClientSocket(var ClientSocket: TClientSocket);
begin
  ClientSocket := TClientSocket.Create(Application);
  ClientSocket.OnError := ClientSocketError;
  ClientSocket.OnRead := ReadSocket;
  ClientSocket.OnConnect := ClientSocketConnected;
end;



Если у Вас есть какие-нибудь предложения исправления или предположения причины ошибки - буду очень благодарен если поделитесь ими со мной :)


 
Digitman ©   (2004-05-20 12:30) [1]

последней строкой в обработчик OnError добавь

Socket.Close;

а вообще бардак у тебя наблюдается в обработчиках и в логике асинхронного коннекта в целом


 
GroZ   (2004-05-20 13:12) [2]

а ClientSocket.Active := False; не тоже что и Socket.Close;?

в чём бардак, поясните?


 
Digitman ©   (2004-05-20 13:33) [3]


> ClientSocket.Active := False; не тоже что и Socket.Close;?


нет, далеко не то же


> Выше приведённый код запускается в Timer-e, каждые 800 мс


и сколько элементов в массиве PrmConns ?
мне непонятно, каков прикладной смысл всей этой петрушки


 
GroZ   (2004-05-21 10:27) [4]

Socket.Close; не помогает ... те же симптомы ...

Так в чём бардак?


 
Digitman ©   (2004-05-21 10:42) [5]

я задал вопросы


 
GroZ   (2004-05-21 10:47) [6]

Удалено модератором
Примечание: Следи за речью...


 
Digitman ©   (2004-05-21 11:13) [7]


> какая на хрен разница сколько элементов в массиве


большая разница ! почему бы мне не предположить, что их там десяток миллионов ? это же - ресурсы , которые ты требуешь от системы ! система же не резиновая !! даже если 2, то не закрывая как положено эти 2 гнезда при неуспешных попытках их коннекта за сотню-другую тиков таймера ты отберешь у системы кучу ресурсов, и система не сможет их выделить иным приложениям (цитирую тебя : "перестаёт работать инет, не работает Outlook Express"), что ты и наблюдаешь !!


> Где какую петрушку ты здесь видиш?


на основании чего ты столь уверен, что 800 мс достаточно для осуществления коннекта с любым сервером ?
объясни простыми и понятными словами, какова твоя общаяч задача


 
GroZ   (2004-05-21 12:14) [8]


> объясни простыми и понятными словами, какова твоя общаяч задача


Программа - Игра в онлайне, децентрализованная, т.е. нет одного главного сервера .. их несколько ...


> на основании чего ты столь уверен, что 800 мс достаточно
> для осуществления коннекта с любым сервером ?


Совершенно я в этом не уверен и даже не надеюсь ... если внимательно рассмотреть код - то видно что попытка присоедениться не происхоит каждый 800 мс .. каждые 800 мс происхотд проверка текущего состояния и если клиент не присоединён к серверу и программа не ждёт результата от прошлой попытка соединения (if not PrmConns[i].ClientSocket.Active and not PrmConns[i].Connecting then begin ... ) то ТОЛЬКО тогда пытаюсь ещё раз приконнектиться ..


 
Verg ©   (2004-05-21 12:41) [9]

И все же в, если ты в onError не закроешь сокет (Scoket.Close),  то будет происходить утечка системного ресурса - дескриптора сокета. Т.ч., после нескольких часов такой работы с утечами дескрипторов всекое может случиться....
ClientSocket.Active := false;
Проверяет, что Active был true и только после этого приступает к отсоединению и закрытию дескриптора (closesocket). Но если соединения не произошло, то ClientSocket.Active := false; не сделает ровным счетом ничего, а тем временем сам дескриптор сокета под попытку соединения был уже выделен (ф-ция socket).
Вот и вся!, "хрен", разница...


 
Digitman ©   (2004-05-21 12:52) [10]


> и если клиент не присоединён к серверу


ну и что ? ну не успел еще внутренний механизм коннекта отработать за эти 800 мс ! при том что сервер, предположим, заведомо активен, но сет.маршрут к нему достаточно сложен, время доставки запроса на коннект + время доставки подтверждения коннекта может занять и секунды и десятки секунд .. ты же , не дождавшись ни события OnConnect (как факт успешного коннекта) ни события OnError() (как факт, например, недоступности/неактивности сервера) тут же делаешь Close() гнезда и пытаешься вновь запустить коннект ..

if not PrmConns[i].ClientSocket.Active and not PrmConns[i].Connecting then begin
       PrmConns[i].ClientSocket.Close;

вот здесь какой смысл закрывать гнездо, если оно и так не активно и не находится в состоянии установления соединения ? Просто сразу делай Open() !

    if PrmConns[i].ClientSocket.Active and PrmConns[i].Connecting then begin
       PrmConns[i].Connecting := False;
    end;

а вот это вообще не нужно здесь - следует просто обработать события OnConnect или OnError, в которых и д.б. сброшен флаг Connecting


 
GroZ   (2004-05-21 12:53) [11]

2 Verg,
На самом деле уже проверил и Scoket.Close вместо ClientSocket.Active := false но к сожелению теже проблемы :(


 
GroZ   (2004-05-21 13:05) [12]

Digitman,
в OnError как раз и скидывется флаг Connecting .. а вот OnConnect ...
Сделал всё как ты говориш ... подожду несколько часов ... посмотрим ..


 
Digitman ©   (2004-05-21 13:12) [13]

проведи ТОЧНЫЙ подсчет : суммируй кол-во выполненных Open() (где угодно) и сопоставь ему кол-во выполненных ClientSocket.Active := False (где угодно вне обработчика OnError) и Socket.Close (в обработчике OnError)


 
Digitman ©   (2004-05-21 13:16) [14]

а для взведения флага Connecting существует событие OnConnecting


 
GroZ   (2004-05-21 14:19) [15]

Digitman,
проверил ... ничего не изменилось ... подсчитал OpenCnt и CloseCnt ... равны (максимум разница 2 как и следовало ожидать)
.
.
:(((((


 
Digitman ©   (2004-05-21 14:29) [16]


> не работает Outlook Express (не может приконнектится к серверу)


и что говорит конкретно ?


 
GroZ   (2004-05-21 14:36) [17]

просто не может присоедениться к серверу .. как если кабель локальной сети вырвать ....

А точно ли TClientSocket.Close закрывает сокет? .. может нужно TClientSocket.Socket.Close ????????


 
Digitman ©   (2004-05-21 14:46) [18]


> просто не может присоедениться к серверу


ОЕ всегда достаточно конкретную диагностику отказа выдает, с кодом ошибки - о ней и спрашиваю


> точно ли TClientSocket.Close закрывает сокет?


точно.

исходники компонента перед тобой, можешь сам убедиться


 
GroZ   (2004-05-21 14:53) [19]

ок, запустил прогу опять ... подожду ещё пару часов и скажу код ошибки ...


 
Digitman ©   (2004-05-21 14:56) [20]


> Также в обработчике ошибки клиент-сокета (ClientSocket.OnError):
>
> PrmConns[i].Connecting := False;


каким образом у тебя обработчик "узнает" о значении i, т.е. индексе элемента массива, с которым ассоциировано гнездо, возбудившее в данный момент событие OnError() ?


 
Digitman ©   (2004-05-21 15:07) [21]

если у тебя происходит ощутимая утечка ресурсов, это и так видно в окне TaskManager"а, и не зачем для этого часами ждать непонятно что


 
GroZ   (2004-05-21 15:36) [22]

procedure TIUS.ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
 ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
  i : integer;
begin
  i := TClientSocket(Sender).Tag;
  case ErrorEvent of
     eeConnect : begin
        PrmConns[i].ClientSocket.Socket.Close;
        CloseCnt := CloseCnt + 1;
        PrmConns[i].CurrPort := PrmConns[i].CurrPort + 1;
        if (PrmConns[i].CurrPort < PrmConns[i].Port.s) or (PrmConns[i].CurrPort > PrmConns[i].Port.e) then PrmConns[i].CurrPort := PrmConns[i].Port.s;
        ErrorCode := 0;
        PrmConns[i].LastErrorTick := GetTickCount;
        PrmConns[i].Connecting := False;
     end;
     eeDisconnect : begin
        Socket.Close;
        CloseCnt := CloseCnt + 1;  
        ErrorCode := 0;
     end;
  end;
end;

В теге слиент-сокетов прописываются их индексы в дин. массиве ...


 
GroZ   (2004-05-21 15:42) [23]

никакой ощутимой утечки ресурсов в TaskManager"е не видно ..


 
Digitman ©   (2004-05-21 16:14) [24]

procedure TIUS.ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
 i : integer;
begin
 i := TClientSocket(Sender).Tag;
 with PrmConns[i] do
 case ErrorEvent of
    eeConnect : begin
       Socket.Close;
       Connecting := False;
       CurrPort := CurrPort + 1;
       if (CurrPort < Port.s) or (CurrPort > Port.e) then CurrPort := Port.s;
       LastErrorTick := GetTickCount;
    end;
 end;
 ErrorCode := 0;
end;


 
GroZ   (2004-05-21 16:24) [25]

И почему это должно работать, а то нет?


 
Digitman ©   (2004-05-21 16:38) [26]


> GroZ   (21.05.04 16:24) [25]


"по кочану" - ответ, думаю, устроит ?

исходники компонента в связи с возникшей проблемой ты не хочешь изучать , выполнять рекомендации в [1] ты не хочешь, прислушаться к [9] ты тоже не желаешь ... что остается ? только "по кочану" ! ... Слепо следуй инструкциям - и да получишь ожидаемый рез-т !

И гонор свой в [6] умерь, коль сам не в состоянии работать с документацией и исх.текстами !

теперь по сабжу ...

если ты русский язык не понимаешь, то я ничем помочь тебе не смогу

цитирую себя:


Digitman ©   (20.05.04 12:30) [1]
последней строкой в обработчик OnError добавь

Socket.Close;


ты ВЫПОЛНИЛ эту рекомендацию ? Нет, не выполнил !!!!!

Какого же ... ты "почемукаешь" сейчас, а ?!


 
GroZ   (2004-05-21 17:17) [27]

Удалено модератором
Примечание: Поумерь пыл... И бегом читать правила поведения на форуме...


 
Digitman ©   (2004-05-21 17:29) [28]


> GroZ   (21.05.04 17:17) [27]


да будет тебе известно, красавец ты наш, LMD ты наш, что "закрывает сокет" - понятие растяжимое,  !

методы TClientSocket.Close и TClientSocket.Socket.Close - методы РАЗНЫХ объектов , выполняются по РАЗНЫМ алгоритмам и каждый из ожидает и/или требует своего вызова в РАЗНЫХ условиях !

а ну марш бегом в исходники !!!


 
apihelp   (2004-05-23 11:41) [29]

Проверяй по одному в отдельных потоках. И используй TStringList.values["n"] = "no"; Ну и таймер+процедура чтоб лист сканила на состояние сокетов. на ком.коннекта except+case
Хотя может не понял суть вопроса.



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

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

Наверх




Память: 0.55 MB
Время: 0.044 c
14-1088652328
Ozone
2004-07-01 07:25
2004.07.18
Linux - безопасность


6-1085394114
ilnarab
2004-05-24 14:21
2004.07.18
Копирование файлов


6-1084747162
Алекс А
2004-05-17 02:39
2004.07.18
Как сделать такое же меню Кодировка как в Интернет Эксплорере?


3-1087771512
dim-
2004-06-21 02:45
2004.07.18
Текущая запись при раcкраске dbgrida


8-1083381315
nikus
2004-05-01 07:15
2004.07.18
Чтение заголовков MPG, ASF и WMV файлов