Takie gniazda są pewne. Zakładając że sieć działa, dane umieszczone w jednym gnieździe pojawią się w drugim gnieździe, poprawne i we właściwej kolejności. Możesz także tworzyć gniazda bez połączenia, ale wtedy nie możesz być pewien po­prawności danych ani ich właściwej kolejności. Dlaczego miałbyś korzystać z gniazd, które nie są pewne? Być może piszesz program posiadający własny protokół zajmujący się obsługą błędów i kolejnością danych. W tym przypadku, powielanie działań na poziomie gniazd jest marnotrawstwem, i niepewne gniazda będą działały dużo efektywniej.
Choć w tej chwili możesz już bezpośrednio korzystać z gniazd, wszystko, do czego mogą posłużyć, to przekazywanie gołych danych. Co zrobić, gdy zechcesz przesłać obiekt C++ z jednego końca połączenia na drugi? MFC umożliwia serializację obiektów poprzez połączone gniazda. Tak jak w przypadku serializacji do pliku i z pliku, możesz zapisywać obiekty do sieci i odczytywać je z drugiej strony.
 
CSocket i obiekty CArchive
Sztuczka pozwalająca na przesyłanie obiektów poprzez sieć polega na powiązaniu obiektu CSocket z obiektem CSocketFile. Sam w sobie, ten obiekt nie jest zbyt użyteczny, możesz jednak połączyć go z obiektem CArchive i przy jego pomocy serializować dane. Dokładne kroki znajdziesz w tabeli 9.3.
Tabela 9.3. Łączenie obiektu CSocket z obiektem CArchiye
1 CSocketFile file(&socket); Tworzy CSocketFile połączony z gniazdem.
2 CArchive input(&file,CArchive::load); Wiąże gniazdo z odczytywanym archiwum.
3 CArchive output(&file,CArchive::store); Wiąże gniazdo z zapisywanym archiwum.
 
Pamiętaj, obiekty CArchive mogą odczytywać lub zapisywać obiekty, ale nigdy w tym samym momencie. Zupełnie akceptowalne jest jednak stworzenie dwóch obiektów CArchive odwołujących się do tego samego gniazda. Możesz dzięki temu odczytywać obiekty z jednego archiwum i zapisywać je do drugiego.
I jeszcze jedno: w przypadku używania CArchive nie możesz korzystać z niepewnych połączeń. Obiekty CArchive traktują gniazda jak pliki, a pliki są pewne.
 
Przejdźmy głębiej: CAsyncSocket
Jeśli potrafisz oprogramować gniazdo, być może nie odpowiada ci, że MFC wykonuje za ciebie tak dużo pracy. Możesz wtedy użyć klasy CAsyncSocket (szczegóły znajdziesz w plikach pomocy MFC). Ta klasa (stanowiąca zresztą klasę podstawową klasy CSocket) umożliwia bezpośredni dostęp do gniazd. Jeśli jednak zdecydujesz się na skorzystanie z CAsyncSocket, będziesz musiał wykonać dużo więcej pracy. Na przykład, użycie CAsyncSocket wymaga ułożenia danych w sieciowej kolejności. Nie możesz także użyć takich gniazd z obiektami CArchive. W praktycznie każdym przypadku, zamiast CAsyncSocket użyjesz CSocket.
Znajdą się jednak przypadki, w których lepiej jest użyć CAsyncSocket. W szczególności, CSocket może czasem się zablokować i spowodować, że podczas oczekiwania na połącze­nie Twój program sprawia wrażenie jakby się zawiesił.
 
Blokujące wywołania
Jedna z największych różnic między odczytem danych z pliku a odczytem z gniazda polega na potencjalnym opóźnieniu. Gdy czytasz obiekt z pliku, to albo w nim jest, albo go nie ma. Jednak w przypadku gniazda nie możesz być pewien czy dane są dostępne. Jeśli spróbujesz odczytać obiekt, Twój program może wstrzymać działanie do momentu, w którym obiekt stanie się dostępny.
Jak temu zaradzić? Blokujące wywołania możesz umieścić w osobnym wątku. Możesz także, w niektórych przypadkach, użyć specjalnych wirtualnych funkcji.
Na przykład, gdy w gnieździe pojawią się dostępne dane, jest wywoływana funkcja OnReceive. Oczywiście, aby przesłonić tę funkcję, musisz wyprowadzić własną klasę z klasy CSocket. CAsyncSocket także zawiera przesłanialne funkcje dla połączeń, ale nie możesz użyć ich z CSocket. Połączenie CSocket albo się powiedzie, albo nie. Jeśli połączenie się nie powiedzie, do ciebie należy podjęcie kolejnej próby.
 
Przykład
Teraz, gdy znasz już klasę CSocket i potrafisz połączyć ją z CArchive, zastanówmy się jak można wykorzystać je w prawdziwym programie. Zdecydowałem się na przetestowanie swoich umiejętności pisząc prostą grę (rys. 9.1). W tej grze staje na przeciw siebie dwóch dowódców. W pierwszej fazie gry umieszcza się na planszy jednostki (powiedzmy czołgi bądź wyrzutnie rakiet). Gdy plansza zostanie wypełniona, komputer jednego z graczy zaczyna pełnić rolę serwera, z którym łączy się drugi gracz. (Aby to przetestować, możesz uruchomić obie strony na tym samym komputerze.) Następnie gracze kolejno bombarduj ą planszę używając myszki. Komputer zgłasza wszystkie pudła i trafienia.
Stworzenie klasy zawierającej informacje przesyłane przez sieć jest proste (patrz tabela 9.4). Dla tego prostego pakietu możesz łatwo napisać funkcje serializacji. Choć w tym przypadku nie jest to wymagane, klasy przeznaczone do serializacji możesz wyprowadzić z klasy CObject.
 
Tabela 9.4. Klas CPacket
cmd Liczba całkowita identyfikująca komendę (CMD_CLICK, CMD_REPLY, CMD_RESIGN)
x Współrzędna X (nie używana z CMD_RESIGN)y Współrzędna Y (nie używana z CMD_RESIGN)
data Znak reprezentujący stan komórki o wsp. (x,y) (nie używane z CMD_CLICK ani CMD_RESIGN)
Serialize Funkcja zapisująca pakiety do Carchive
 
W przypadku naszej gry komunikacja przebiega zgodnie z określonym protokołem. Host (serwer) wysyła pakiet CMD_CLICK. Klient odpowiada pakietem CMD_REPLY. Następnie klient przesyła swój pakiet CMD_CLICK i odbiera pakiet CMD_REPLY. Zamiast polecenia CMD_CLICK program może wysłać polecenie CMD_RESIGN aby zakończyć grę.



 

 

 

 

 

 

 

 

 

 

 

 

   
 
  W tym momencie możesz bezpośrednio użyć pary obiektów CSocket do przekazywania danych tam i z powrotem, pomiędzy dwoma komputerami (używając funkcji...
Pomodliłem się do każdego boga jaki istniał bym był w wstanie wkurzyć tę kobietę do granic możliwości.