minikomunikator, c++

0

Cześć :)
Piszę sobie minikomunikator w Qt i mam do Was pewne pytanie:
Rozważmy wysyłanie wiadomości. Mamy tutaj dwie możliwości:
1.
Wg mnie powinienem to zaimplementować to tak:
Serwer po otrzymaniu wiadomości zapisuje do bazy danych wiadomość po czym sprawdza czy adresat jest online. Jeżeli jest to wysyła mu komunikat. Na ten komunikat klient daje standardowe zapytanie o nowe wiadomości, a serwer mu je zwraca.
2.
Klient ma osobny wątek, który co jakiś czas wysyła zapytanie do serwera z zapytaniem, czy nie ma czasem dla niego nowych wiadomości. Tu jednak odrzuca mnie trochę fakt, że serwer będzie zalewany ciągłymi zapytaniami, ale wydaje mi sie, że i tak muszę mieć w kliencie jakiś wątek, który stale ( co to znaczy stale?) będzie sprawdzał połączenie.
Doradźcie mi tu trochę :)

1
mielony napisał(a):

Cześć :)
1.
Wg mnie powinienem to zaimplementować to tak:
Serwer po otrzymaniu wiadomości zapisuje do bazy danych wiadomość po czym sprawdza czy adresat jest online. Jeżeli jest to wysyła mu komunikat. Na ten komunikat klient daje standardowe zapytanie o nowe wiadomości, a serwer mu je zwraca.

Masz zamiar tworzyc archwium wiadomosci na serwerze? Bo jezeli nie to zapis w bazie danych komunikatu dla uzytkownika online mija sie z celem. Serwer powinien wyslac do klienta wiadomosc jezeli jest online lub zapisac ja w bazie danych w przeciwnym przypadku.

Edit: z drugiej strony wypadaloby przechowywac gdzies wiadomosci, ktorych odbiorca nie potwierdzil. Pytanie tylko czy trzeba do tego celu wykorzystywac baze danych? Z jednej strony jest to wygodne, a z drugiej to nie wiem czy optymalne - nalezaloby sie troche nad tym zastanowic :)

Pytanie serwera o nowe wiadomosci wydaje mi sie bezcelowe. Klient powinien potwierdzic odebranie wiadomosci i tyle wystarczy.

mielony napisał(a):

Cześć :)
2.
Klient ma osobny wątek, który co jakiś czas wysyła zapytanie do serwera z zapytaniem, czy nie ma czasem dla niego nowych wiadomości. Tu jednak odrzuca mnie trochę fakt, że serwer będzie zalewany ciągłymi zapytaniami, ale wydaje mi sie, że i tak muszę mieć w kliencie jakiś wątek, który stale ( co to znaczy stale?) będzie sprawdzał połączenie.
Doradźcie mi tu trochę :)

Ja bym to zrobil tak: klient w ogole sie nie pyta o nowe wiadomosci - dostaje wszystkie zalegle wiadomosci po zalogowaniu sie w sposob automatyczny. Jak je dostanie to wysle potwierdzenie ze dostal i na tej podstawie serwer wie zeby juz wiecej ich nie wysylac. W momencie kiedy serwer odbierze nowe wiadomosci przeznaczone dla konkretnego klienta to je po prostu przekazuje klientowi. Klient nie musi o nie pytac bo o nowych wiadomosciach powie mu serwer.

0

ok, w jaki sposób serwer może powiedzieć klientowi? Mam mieć tabelę userów, którzy się logowali i trzymać w niej kolumny numer oraz IP?
IP może być zmienne, zatem żeby wysłać wiadomość do konkretnego klienta musiałbym mieć jego aktualne IP.

1

Nie wiem jak chcesz rozwiazac komunikacje. Jezeli wykorzystasz do komunikacji gniazda to adres IP bedzie Cie interesowal glownie po stronie klienta i glownie w trakcie nawiazywania polaczenia. Jezeli klient polaczy sie z serwerem to wlasciwie nie musisz juz sie zadnymi adresami IP przejmowac. Po stronie serwera zaczniesz pisac do gniazda reprezentujacego klienta a klient bedzie czytal z gniazda reprezentujacego serwer.

Adres IP to moze i byc zmienny, ale po stronie klienta. Po stronie serwera powinien byc raczej staly i na dodatek zewnetrzny. Poniewaz to klient musi znac adres serwera w celu nawiazania polaczenia nie masz sie co przejmowac zmiennoscia adresu klienta. Po prostu serwer bedzie nasluchiwal pod okreslonym adresem na okreslonym porcie. Jezeli wykryjesz probe nawiazania polaczenia to je akceptujesz i zapamietujesz gdzies gniazdo klienta, ktory sie polaczyl. Nastepnie w celu wyslania wiadomosci po prostu piszesz do gniazda i reszta sie nie martwisz.

W Qt za duzo nie pisalem, ale wydaje mi sie, ze powinienes zainteresowac sie takimi klasami jak QTcpServer i QTcpSocket .

Tu masz pierwszy z brzegu przyklad chata: http://thesmithfam.org/blog/2009/07/09/example-qt-chat-program/

0

dobrze, w takim razie jeżeli serwer przyjmie od kogoś wiadomość i jej adresatem jest 123456, to serwer musi sprawdzić czy klient jest na liście socketów ( liniowo) w następujący sposób:
Mam obiekt klienta, gdzie mam zapamiętatany jego socket i nr, który go reprezentuje. Przeszukuje wszystkich klientów w celu znalezienia właściewego numeru?
Chodzi tu o sam sposób, bo można oczywiście szukać w czasie logarytmicznym. ( numery są porównywalne)

1
mielony napisał(a):

dobrze, w takim razie jeżeli serwer przyjmie od kogoś wiadomość i jej adresatem jest 123456, to serwer musi sprawdzić czy klient jest na liście socketów ( liniowo) w następujący sposób:

Mam obiekt klienta, gdzie mam zapamiętatany jego socket i nr, który go reprezentuje. Przeszukuje wszystkich klientów w celu znalezienia właściewego numeru?

Tak, mniej-wiecej o to chodzi. Jezeli znajdziesz adresata na liscie soketow to przesylasz do niego komunikat nadawcy (piszesz do socketa adresata). Tylko musisz pamietac o tym aby w razie utraty polaczenia zaktualizowac liste socketow.

No i inna sprawa ze nie tylko szukasz numerow ale szukasz tez socketow. Jezeli z socketa (nadawcy) przyjdzie jakas wiadomosc to musisz poszukac numeru (nadawcy), zeby wiedziec kto to przyslal. Jak juz bedziesz mial ten numer (nadawcy) to szukasz gniazda (odbiorcy) na podstawie numeru (odbiorcy). Numer odbiorcy ustalisz na podstawie pakietu wyslanego przez nadawce (w pakiecie powinna sie znajdowac informacja do kogo chce wyslac i co). Odbiorcy wysylasz nie tylko wiadomosc ale takze informacje o identyfikatorze nadawcy, tak zeby wiedzial od kogo to przyszlo.

mielony napisał(a):

Chodzi tu o sam sposób, bo można oczywiście szukać w czasie logarytmicznym. ( numery są porównywalne)

Sposob wydaje sie ok, tylko jak sam zauwazyles niekoniecznie musisz wyszukiwac dane w czasie liniowym. Lepiej byloby uzyc dwoch kolekcji typu QHash. Kluczem pierwszej z nich bylby identyfikator uzytkownika, wartoscia socket. W drugiej odrwotnie.

Takie rozwiazanie powinno pozwolic Ci wyszukiwac w senownym czasie uzytkownika na podstawie gniazda i gniazda na podstawie uzytkownika.

Sa oczywiscie kolekcje, ktore spelniaja obie te funkcje na raz, ale nie wiem czy znajdziesz je w Qt / standardowym C++. Jezeli tak to je wykorzystaj (lepiej pracowac na jednej kolekcji niz na dwoch), jezeli nie to albo skorzystaj z zewnetrzenej biblioteki albo pozostan przy dwoch kolekcjach.

1

Robiłem kiedyś coś bardzo podobnego do tego co chcesz zrobić.

Zacznij od przeczytania jakiegoś artukłu/poradniki o programowaniu sieciowym pod Windowsem to pozwoli Ci już zrozumieć jak większość tych rzeczy działa.

Gdy ja pisałem serwer to jako, że to był projekt tylko do nauki i poduczenia się czegoś to serwer dla każdego nowego podłączonego klienta tworzył nowy wątek i obsługiwał w nieskończonej pętli danego klienta aż do utracenia z nim połączenia. Wybrałem takie podejście bo używałem bokujących socketów.

A klient bardzo podobnie działał - 1 wątek do pisania wiadomości w konsoli i ich wysyłania, a drugi to nieskończona pętla, gdzie odbierał komunikaty od serwer aż utracił z nim połączenie.

Jeśli np będziesz chciał wysłać do kogoś wiadomość, a on nie będzie podłączony do serwera to możesz np tworzyć osobny plik w którym będziesz zapisywał wszystkie takie wiadomości np w fomracie:

wiadomosc;id_klienta
wiadomosc;id_klienta

id_klienta to musiałby być jakis unikalnie nadawny numerek przez serwer, ponieważ w końcu z jednego adresu IP może być wiele użytkowników - chyba że wyłączasz taką możliwość to wtedy:

wiadomosc;ip
wiadomosc;ip

I gdy do serwera przyjdzie nowe połączenie z danego adresu IP to wyślesz mi wszystkie zaległe wiadmości.

0

Tak, mniej-wiecej o to chodzi. Jezeli znajdziesz adresata na liscie soketow to przesylasz do niego komunikat nadawcy (piszesz do socketa adresata). Tylko musisz pamietac o tym aby w razie utraty polaczenia zaktualizowac liste socketow.

Ok, ale myślę też o tym tak:
Mam kolekcję klientów obecnie wpiętych. Ja widzę to tak:
Każdy klient ma wątek, który co jakiś czas (minutę?) wysyła do serwera komunikat: Drogi serwerze, jestem nadal podłączony. Zapamiętuję dla klienta ten czas jako pole.
W takiej sytuacji serwer również ma wątek, który przegląda ( ciągle?) kolekcję klientów i jeżeli nie przedłużył czasu to go odpinam.

Inną sprawą jest fakt, że po wysłaniu wiadomości do klienta i tak muszę brać potwierdzenie dojścia wiadomości. To będzie jedyne zapewnienie.

Pytanie:
O serwerze QTcpServer pisze, że działa on asynchronicznie, czy może mi ktoś powiedzieć co to dokładnie znaczy :)?
pozdrawiam :)

0
mielony napisał(a):

O serwerze QTcpServer pisze, że działa on asynchronicznie, czy może mi ktoś powiedzieć co to dokładnie znaczy :)?
pozdrawiam :)

To znaczy mniej więcej tyle, że nie musisz specjalnie tworzyć dodatkowego wątku, aby serwer mógł odbierać połączenia. http://xion.org.pl/2008/03/10/asynchronicznosc-kontra-watki/ <-- tu jest fajnie napisane, o co chodzi z asynchronicznością.

1
mielony napisał(a):

Ok, ale myślę też o tym tak:
Mam kolekcję klientów obecnie wpiętych. Ja widzę to tak:
Każdy klient ma wątek, który co jakiś czas (minutę?) wysyła do serwera komunikat: Drogi serwerze, jestem nadal podłączony. Zapamiętuję dla klienta ten czas jako pole.
W takiej sytuacji serwer również ma wątek, który przegląda ( ciągle?) kolekcję klientów i jeżeli nie przedłużył czasu to go odpinam.

Moim zdaniem dobrze do tego podchodzisz. Pamietaj jednak, ze rozwiazanie, o ktorym piszesz nie jest po to aby w normalny sposob obsluzyc zerwanie polaczenia. Stosuje sie je po to aby zrobic porzadek z klientami ktorzy rozlaczyli sie z serwerem w nietypowy sposob.

W normalnej sytuacji powinienes reagowac takze na zdarzenie zerwania polaczenia i zdarzenia bledow komunikacji. Jezeli wiec obsluzysz zdarzenie rozlaczenia sie klienta to wtedy go odlaczasz od razu i nie czekasz az uplynie iles tam minut od jego ostatniej aktywnosci.

Rowniez pozdr :)

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