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

Awaria serwera, a próby automatyczne nawiązywania połączeń z nim.
Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
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.

Kopiuj
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;
edytowany 1x, ostatnio: Artur Protasewicz
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
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


edytowany 1x, ostatnio: Patryk27
Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
0

Dzięki.

Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
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.

Patryk27
W takim razie bez problemu powinno działać. Ew. możesz podejść w drugą stronę i wykorzystać multicast - tzn. zamiast sprawdzać co chwilę czy serwer żyje, możesz ze strony serwera wysłać do wszystkich w podsieci (wykorzystując właśnie multicasting) pakiet jestem żywy i wtedy dopiero klienci mogą zaczynać się łączyć.
Artur Protasewicz
Artur Protasewicz
Rozważam też umieszczenie na serwerze komponentów TClientSocket, a na klientach TServerSocket. Czy o to chodzi? No i właśnie serwer by się próbował łączyć ze stanowiskami w sieci.
Patryk27
Nie wiem niestety jak realizuje się multicasting w Delphi, ale prawdopodobnie coś w taki deseń powinno zadziałać.
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:minuta
  • Lokalizacja:Poznań
  • Postów:8759
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).


edytowany 2x, ostatnio: cerrato
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
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ć.


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
Patryk27
weź pod uwagę, że musisz najpierw na serwerze zarejestrować listę klientów aby serwer wiedział kogo budzić chyba że wykorzysta multicasting
abrakadaber
abrakadaber
ale akurat to zdanie dotyczyło tego Rozważam też umieszczenie na serwerze komponentów TClientSocket, a na klientach TServerSocket. No i właśnie serwer by się próbował łączyć ze stanowiskami w sieci.
Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
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ą.

cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:minuta
  • Lokalizacja:Poznań
  • Postów:8759
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.


Artur Protasewicz
Artur Protasewicz
Adresy klientów są znane. I serwera też.
cerrato
No to chyba najsensowniej jest zrobić tak, jak napisałem powyżej - klient po odpaleniu próbuje się połączyć, a jak się nie uda to zaczyna czekać na sygnał ze strony serwera
Artur Protasewicz
Artur Protasewicz
Użyłem i timera dla TClientSocket. A jak inaczej? Na multicast też musi jakoś czekać.
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
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.


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:minuta
  • Lokalizacja:Poznań
  • Postów:8759
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"


Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
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.

edytowany 1x, ostatnio: Artur Protasewicz
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:minuta
  • Lokalizacja:Poznań
  • Postów:8759
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.


Artur Protasewicz
Artur Protasewicz
  • Rejestracja:ponad 15 lat
  • Ostatnio:ponad 5 lat
  • Postów:233
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.

Artur Protasewicz
Artur Protasewicz
Tak "na chłopski rozum" serwer albo z jakiegoś powodu jest restartowany, a jak już padnie to na znacznie dłużej.
Patryk27
Btw, fachowo coś takiego nazywa się exponential backoff.
abrakadaber
abrakadaber
nie - czas próby to jest właśnie timeout - jeśli po zadanym czasie (timeout) nie uda się połączyć to dostajesz wyjątek. Wtedy odpalasz timera, który odlicza Ci czas do ponownej próby
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:minuta
  • Lokalizacja:Poznań
  • Postów:8759
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.


Artur Protasewicz
Artur Protasewicz
Głównym zadaniem aplikacji jest komunikacja sieciowa i nawet ta jest bardzo prosta - tekstowe symbole, liczby itp. jako uzupełnienie tego w czym łatwo o pomyłkę np. w rozmowie telefonicznej, a co można skopiować i wkleić, bo już istnieje w jakimś dokumencie w formie elektronicznej.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)