Myślisz, że zarabiasz tyle, na ile zasługujesz? Zapraszamy do wzięcia udziału w anonimowej ankiecie.
2

1

Od pewnego czasu przymierzam się do pewnego projektu. Rozpisując wszystko zacząłem się zastanawiać jak dobrze napisać serwer(najważniejszą część projektu). Serwer będzie konsolową aplikacją.

Pierwszym problemem jest główna pętla. W przykładach jakie do tej pory spotkałem jest coś na wzór:

do
{
    // jakis kod
}while(exit != true)

To rozwiązanie wydaje mi się być zbyt proste aby było idealne :)

Drugim (największym problemem) jest zaprojektowanie klasy "sesji". Każde konto ma mieć możliwość obsłużenia M połączeń przychodzących i N wychodzących.
Przykładowo: Użytkownik łączy się z komputera A i otwiera strony devpytania.pl i devblogi.pl pewne dane są trzymane w sesji(czas od pierwszego połączenia). Po chwili użytkownik ponownie łączy się, tym razem z komputera B. Otwierając jakaś stronę dane mają być wysyłane do podłączonych klientów (w tym wypadku komputera A i B)
Użytkownik <--> Serwer <--> NET
(Jasno opisane ? :>)
Połączenia powinny być trzymane w tablicach. czy w jakiś inny sprytny sposób?

Może projektowaliście kiedyś coś podobnego?

flag

3 Answers

3

Właściwie de facto sprowadza się do takiej (nie)skończonej pętli :).

Jeśli używasz Socketów do realizacji połączenia sieciowego, to wszystko ( w dużym uproszczeniu) sprowadza się mniej więcej do tego (Przykład z Javy, ale w .NET powinno być podobnie)

ServerSocket serverSocket;
while (true)
{
     Socket socket = serverSocket.accept();
     new ServeClient(socket);
}

Gdzie ServeClient to obiekt będący wątkiem lub procesem. To, czy to będzie wątek czy proces zależy od Ciebie. Wątki z reguły są szybsze i działają na współdzielonych zasobach, natomiast procesy zapewniają większą stabilność (jeśli wywali się proces, to tylko ten jeden, a nie cały serwer).

Co do realizacji sesji, potrzebna Ci po prostu jakaś współdzielona struktura danych. Jeśli implementacja jest na wątkach, wystarczy jakaś statyczna struktura danych w pamięci współdzielona między wątkami. Przy procesach jest trochę trudniej, bo trzeba sobie zorganizować komunikację między procesami. Pamiętaj tylko, aby tą współdzieloną strukturę danych umieścić w sekcji krytycznej, tzn zabezpieczyć ją przed sytuacją wyścigu (w .NET służy do tego instrukcja lock ZTCW).

link|flag
3

Pętla główna zazwyczaj tylko nasłuchuje nowych połączeń po czym deleguje je do osobnych wątków, gdzie są obsługiwane. Jej kod musi być maksymalnie prosty w swojej logice. Oczywiście nie oznacza to, że jest to prosty kod w programie. Jednakże idea jest bardzo zbliżona do tej, którą zaprezentowałeś.

Co do sesji to najłatwiej jest powiązać dane z sesji z loginem użytkownika i w bazie danych utrzymywać sesję na poziomie zalogowanego użytkownika. Działa to tak:

  1. Loguję się na stanowisku A - to zapisujemy do bazy i dokonuję jakiś modyfikacji tak, że aktualny stan aplikacji jest zapisywany do bazy.
  2. Przechodzę na stanowisko B i tam loguję się.
  3. Serwer stwierdza, że jestem aktywny na innym stanowisku, odczytuje stan sesji z bazy i serwuje mi go na nowym stanowisku.
link|flag
3

Istnieje wiele różnych sposobów realizacji takiego serwera. Możesz mieć np.:

  1. Pojedyńczy wątek do obsługi wszystkiego używający select() albo epoll()
  2. Wątek główny i oddzielne wątki do obsługi aktywnych połączeń.
  3. Jakaś mieszanka dwóch powyższych.

Stan użytkownika musi obejmować wszystkie jego aktywne połączenia. Na nich pewnie chcesz nasłuchiwać żądań otwarcia jakieś strony, potem je wykonywać i odsyłać kopię odpowiedzi. Trzymać możesz je w czymkolwiek, byle by dostęp był synchronizowany.

Jeśli już piszesz w C#, to jest to dobre miejsce do użycia Reactive Framework. Chociaż jak widzę sockety nie generują zdarzeń, ale możesz je obudować i generować sobie zdarzenia typu: NowePołączenie, Żądanie, itp.

link|flag

Your Answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.