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