Awaria serwera, a próby automatyczne nawiązywania połączeń z nim.

0

Robię prosty komunikator, oparty o komponenty TClientSocket i TServerSocket.

Chciałbym, aby aplikacje klienckie automatycznie nawiązywały połączenie z aplikacją serwera, kiedy tylko jest on dostępny w sieci (lokalnej).

Czy coś złego dzieje się w sieci, kiedy serwer jest niedostępny, np. z powodu awarii, a aplikacje klienckie cały czas próbują z nim nawiązać połączenie?

Próbę automatycznego nawiązania połączenia realizuje poniższy kod, przy czym zamiast localhost są adresy komputerów w sieci, a host to adres serwera.

Zakładam, że TimeOut byłby bardzo duży – na tyle, żeby próby nawiązania połącznia trwały ok. 20 godzin.

Komputerów w sieci ma docelowo być ok. 100.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Enabled := False;
  Timer1.Interval := 10000;
  ClientSocket1.Address := '127.0.0.1';
  ClientSocket1.Port := 60000;
  ClientSocket1.Host := '127.0.0.1';
  Counter := 0;
  TimeOut := 10;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if (not ClientSocket1.Socket.Connected) and (Counter < TimeOut) then
  begin
    Inc(Counter);
    ClientSocket1.Active := True;
  end
  else
    Close;
end;

procedure TForm1.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  ErrorCode := 0;
  ClientSocket1.Active := False;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Timer1.Enabled := False;
  ClientSocket1.Active := False;
end;
1

Czy coś złego dzieje się w sieci, kiedy serwer jest niedostępny, np. z powodu awarii, a aplikacje klienckie cały czas próbują z nim nawiązać połączenie?

Nie, nic złego (cokolwiek by się pod tym pojęciem kryło) się nie stanie - chyba że będziesz spamował żądaniami co milisekundę, no ale to już kwestia dobrania parametrów :-P

0

Dzięki.

0
Patryk27 napisał(a):

chyba że będziesz spamował żądaniami co milisekundę, no ale to już kwestia dobrania parametrów :-P

10 sekund to wystarczająco często. Może nawet 1 minuta.

1

Ja w tej chwili piszę także aplikację działającą w ramach sieci LAN i miałem podobny "problem" do przemyślenia, aczkolwiek u mnie kwestia była trochę inna - chodziło o automatyczne wykrywanie serwera. Rozwiązałem to przez multicast (https://pl.wikipedia.org/wiki/IP_Multicast) - czyli klienci nasłuchują, a w chwili kiedy serwer się pojawia to rozgłasza w ramach sieci multicastem, że zaczął działać. W ten sposób wszyscy klienci będący "na nasłuchu" od razu dostają stosowne powiadomienie, a do tego (nie wiem, czy to ma dla Ciebie znaczenie, ale dla mnie miało ogromne) od razu są poinformowani o adresie IP nadawcy, więc wiedzą z kim mają się komunikować (istotne dla mnie było, żeby klienci działali całkowicie autonomicznie i bez konieczności konfiguracji, żeby sami mogli wykryć serwer i się do niego podpiąć bez jakiejkolwiek ingerencji ze strony użytkownika).

A odpowiadając na pytanie - nie, nic się złego nie stanie, tylko po prostu generujesz niepotrzebny ruch, ale i tak jeśli co kilka(naście/dziesiąt) sekund klienci wyślą pakiety, który "pójdą w próżnię" to nic się nie stanie, sieć od tego nie padnie (a jeśli padnie, to znaczy że i tak miała ze sobą problemy).

0

nie bardzo rozumiem o co Ci chodzi z tym timeout na 20h - timeout ustaw krótki (standardowo jest chyba 5 s) i taki spokojnie wystarczy. Następnie odpytywanie ustaw co jakiś czas (to zależy jak bardzo chcesz mieć dostęp do serwera już a nie np. z 10 minut) i tyle. Lokalnie rozwiązaniem może być multicast jak sugerowali już koledzy, przy serwerze w WANie to już nie przejdzie.

Co do pomysłu aby serwer "budził" klientów po restarcie (czyli każdy klient robi za serwer a serwer robi za klienta) to weź pod uwagę, że musisz najpierw na serwerze zarejestrować listę klientów aby serwer wiedział kogo budzić.

0
cerrato napisał(a):

czyli klienci nasłuchują, a w chwili kiedy serwer się pojawia to rozgłasza w ramach sieci multicastem, że zaczął działać.

A co z klientami, którzy dopiero się logują? Na chwilę obecną jestem po próbie wykorzystania pokazanego kodu od strony serwera i prawdę mówiąc bardziej mi to pasuje. Ale może robię błąd stosując tylko w tej próbie po stronie serwera TClientSocket, a po stronie klienta tylko TServerSocket? Rzeczywiście klienci nasłuchują.

0

A co z klientami, którzy dopiero się logują?

No to zależy od wizji, jaką przyjmiesz. Podstawowa sprawa - czy klienci mają mieć jakiś z góry określony/skonfigurowany adres serwera, czy (jak w moim przypadku) ten adres jest nieznany i ma być wykrywany samoczynnie?

Jeśli znamy adres serwera (a tak właśnie rozumiem Twój zapis z pierwszego posta - "zamiast localhost są adresy komputerów w sieci, a host to adres serwera"), to sprawa jest prosta: po odpaleniu klienta, próbuje się on podłączyć do serwera. Jeśli się udaje to po prostu się "podpina" i zaczyna się z nim komunikować. Jeśli natomiast to się nie uda - przechodzi w tryb oczekiwania, z którego może go "wybudzić" otrzymany od serwera multicast w chwili, w której serwer zaistnieje w sieci.

1

ja tylko uzupełnię - przy broadcast wysyłasz dane nie na konkretny adres ale na adres z końcówką 255 (przy masce /24) i wtedy to co wyślesz jest słane do wszystkich adresów z danej podsieci więc nie musisz "rejestrować" nigdzie klientów.

0

Użyłem i timera dla TClientSocket. A jak inaczej? Na multicast też musi jakoś czekać

Powiem szczerze - za bardzo nie rozumiem, o co Ci chodzi :(
Odnośnie czekania - nie masz żadnych timerów, a jedynie po prostu obsługujesz zdarzenie, które zostanie wywołane w chwili otrzymania zgłoszenia multicast ze strony serwera (być może to, że się nie dogadujemy wynika z tego, że ja pisałem w oparciu o Indy, a Ty TClientSocket i TServerSocket). W tej chwili siedzę na innym kompie, na którym nie mam tego projektu (i nie chce mi się go szukać, ściągać itp.) więc Ci nie pokażę, ale postaram się pod wieczór wkleić jak to powinno działać. A w tym czasie proszę, żebyś wyjaśnił dwie rzeczy - czyli o co chodzi z timerem i oczekiwaniem oraz to, o czym pisał wcześniej @abrakadaber - "nie bardzo rozumiem o co Ci chodzi z tym timeout na 20h"

0
cerrato napisał(a):

być może to, że się nie dogadujemy wynika z tego, że ja pisałem w oparciu o Indy, a Ty TClientSocket i TServerSocket). "nie bardzo rozumiem o co Ci chodzi z tym timeout na 20h"

Robię nie na Indy, a na TServerSocket, TClientSocket. Podałem ten czas 20h dla przykładu, żeby był w miarę długi. Na dzisiaj nie wiem ile to oczekiwanie będzie trwać. Krócej niż 4-8 godzin. Tu chodzi o czas trwania 1 zmiany w firmie.

0

Z tego co kojarzę, tak długie timeouty nie mają większego sensu. Raczej w takich sytuacjach stosuje się jakiś "życiowy" czas - rzędu kilku sekund, a po porażce chwilę później stara się ponowić transmisję - i tak do skutku.

0
cerrato napisał(a):

Raczej w takich sytuacjach stosuje się jakiś "życiowy" czas - rzędu kilku sekund, a po porażce chwilę później stara się ponowić transmisję - i tak do skutku.

Czyli w uproszczeniu, rozwiązaniem będzie zastosowanie dwóch timerów - jednego na czas kilku sekund tj. próby połączenia z serwerem i drugiego między próbami nawiązania połączenia np. co kilka minut.

0

To jeszcze zależy od tego, jaką masz architekturę aplikacji i na ile komunikacja sieciowa jest istotna dla jej działania. Możesz zrobić timery i w wypadku komunikatora ma to sens. Często w aplikacjach, które się komunikują z siecią "w tle" stosuje się osobny wątek, który odpowiada za obsługę sieci, ale jednocześnie nie blokuje głównego wątku aplikacji. Aczkolwiek - jak napisałem przed chwilą - w Twoim przypadku nie wiem, czy to jest potrzebne, bo zasadniczo komunikator bez serwera jest raczej bezużyteczny. Co innego, jeśli sam komunikator jest tylko jakimś małym elementem większej aplikacji, która poza tym robi jeszcze inne rzeczy - wtedy sensowne może być wyłączenie tematów sieciowych do osobnego wątku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1