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

Вниз

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

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

Наверх





Память: 0.53 MB
Время: 0.037 c
1-1089144177
whitespider
2004-07-07 00:02
2004.07.18
Как связаться с Маткадом


3-1088133459
RDen
2004-06-25 07:17
2004.07.18
Фильтрация у таблицы с условием частичного совпадения.


1-1088736123
qwerg
2004-07-02 06:42
2004.07.18
Скины


14-1088388530
Думкин
2004-06-28 06:08
2004.07.18
С днем рождения! 27 июня


1-1089194369
Abajun
2004-07-07 13:59
2004.07.18
преобразование строки в массив и обратно





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский