arrowHome Tuesday, 07 September 2010  



 
Google
Web winapi.org
Main Menu
Home
News
FAQ
Links
Download
Kontakt
FORUM

Artykuły
Podstawy
GDI i Multimedia
Kontrolki
inne
Winapi + asm
WinSock
Soft
Login Form
Login

Hasło

Zapamiętaj mnie
Nie pamiętasz hasła?
Nie masz konta? Załóż je sobie
Winsocket czyli Internet od środka Drukuj E-mail
Oceny: / 104
KiepskiBardzo dobry 
Napisał Mironix   
Thursday, 09 December 2004

 

 

Na pewno brakowało wam komunikacji ze światem. Po to wymyślono Internet aby powstawały aplikacje działające pod siecią a winsocket bardzo to ułatwia. Będąc ostatnią 7 warstwą sieci(czyli warstwą programową) nie musimy się przejmować organizacją sieci na której program działa(np. czy jest to ethernet czy token ring nie ma znaczenia).Na początek musimy zadać sobie pytanie "Jak się do tego zabrać?". Odpowiedź jest jedna: musi być klient i musi być serwer. To jedyna zasada przy winsocket. A każdy klient i Każdy serwer ma adres ip lub host. Ponieważ będziemy Używać protokołu TCP/IP potrzebny nam jest jeszcze port na którym serwer po swojej stronie będzie "słuchać" a po drugiej klient który na tym samym porcie będzie "mówił" czego chce(chyba że będzie to transfer pliku to wtedy będzie prawdziwie "krzyczał").Jeżeli chodzi o testowanie aplikacji sieciowych wystarczy własny komp ponieważ ma on adres ip i host(localhost,127.0.0.1). Pamiętaj że serwer nasłuchujący na danym porcie musi mieć wyłączność na jego używanie, inaczej socet się nie zagnieździ. Ok no to zaczynamy:

 

1.Start Winsocketów

 

Winsocket potrzebuje uruchomienia czegoś takiego jak WSA jest to składnik Windows pozwalający na komunikacje z innymi komputerami jednak każda aplikacja musi go dla siebie uruchomić robi się to następująco:

 

int blad;

WORD wersja;

WSADATA wsaData;

wersja = MAKEWORD( 2, 0 );

blad = WSAStartup(wersja, &wsaData );

 

if ( blad != 0 )

{

MessageBox(hWnd,"error WSA","ERROR",MB_OK);

WSACleanup();

}

 

if ( LOBYTE( wsaData.wVersion ) != 2 ||

HIBYTE( wsaData.wVersion ) != 0 )

{

MessageBox(hWnd,"error zła wersja winsocket","ERROR",MB_OK);

WSACleanup();

}

 

Nie jest to aż takie straszne jak wygląda. Najgorsza jest funkcja MAKEWORD(LOBYTE,HIBYTE) która tworzy zmienna typu WORD której "niskie" bity ustawia na 2 a "wysokie" na 0.Służy to jedynie włączeniu Winsocket 2.0 (są stabilniejsze i momentami szybsze od poprzednich) bo  w WSAStartup podajemy wersje i strukturę która zwraca nam wersje uruchomionego Winsocket. Jeżeli coś działa niepoprawnie zamykamy WSA i wyrzucamy messageBox'a z informacją o błędzie.

 

2.Serwer

 

Serwer wykonuje 3 czynności:

-Nasłuchuje

-Przetwarza

-Odpowiada

Żeby serwer mógł nasłuchiwać musi najpierw powstać socket a żeby powstał socket najpierw musimy ustalić jego parametry(biblioteki i nagłówki na dole strony)

 

SOCKET nasluchujacy, polaczony;

nasluchujacy =  socket( AF_INET, SOCK_STREAM, 0 );

 

I masz już socketa niestety to nie koniec. Nasz socket jest tylko socketem korzystającym z TCP/IP(AF_INET) na zasadzie strumieniowego połączenia(SOCK_STREAM) bez żadnych dodatkowych flag(0).musimy sprecyzować jego zadania:

 

int rozmiar

struct sockaddr_in sin;

memset( &sin, 0, sizeof(sin) );

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = INADDR_ANY;

sin.sin_port = htons(port);

rozmiar = sizeof(sin);

if ( bind(nasluchujacy,(struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR )

{

    MessageBox(hWnd,"bind - błąd","błąd",MB_OK);

            WSACleanup();

}

 

Mamy już socket ustawiony na tym porcie na jakim chcemy. Pojawiła się struktura sockaddr_in przechowuje ona parametry naszego socketa a funkcja bind mu je przypisuje(w kliencie robimy to przy łączeniu)sprawdzamy też czy przypadkiem wszystko poszło po naszej myśli. Wystarczy nam wiedzieć że składnik sin_family struktury sockaddr_in to znowu wskazanie użycia TCP/IP, addr to adres do którego socket się łączy ponieważ jest to socket nasłuchujący ustawiamy mu ze może się połączyć z każdym adresem(odwrotnie każdy adres może połączyć się z serwerem)kolejny to port pod który podłączy się klient. htons to funkcja konwertująca numer portu na typ który zrozumie socket. Ok no to teraz do funkcji bind() pierwszy parametr to socket któremu przydzielamy parametry, drugi to struktura z parametrami(a konkretnie adres do niej dlatego tyle nawiasów i & przed nazwą)ostatni to wielkość struktury konfigurującej. Teraz wystarczy włączyć nasłuchiwanie i wysyłanie komunikatów(tryb asynchroniczny)WSA funkcjami:

 

if (listen(nasluchujacy,SOMAXCONN)==SOCKET_ERROR)

{

            MessageBox(hWnd,"error listen","ERROR",MB_OK);

            WSACleanup();

}

WSAAsyncSelect(nasluchujacy,hWnd,WM_USER,FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE);

 

Teraz masz już program nasłuchujący na zadanym przez ciebie porcie wysyłający komunikat WM_USER ze składnikami FD_ACCEPT(prośba o zaakceptowanie),FD_CONNECT(co ma program zrobić podczas połączenia),FD_READ(co zrobić kiedy nam ktoś coś przysyła) i FD_WRITE(co zrobić jak ktoś prześle nam plik).funkcja listen() pobiera tylko stworzony przez nas socket i ilość połączeń jaką chcemy odbierać my chyba nie będziemy ograniczać i będziemy przyjmować wszystkie. chyba że coś jest nie tak (na przykład coś jest źle ustawione) to musimy wyłączyć WSA i wyrzucić messag'a o błędzie. Kolejna funkcja każe socketowi wysyłać komunikaty które chcemy trzymywać. Pierwszy parametr to socket którym nasłuchujemy drugi to uchwyt okna do którego mają przychodzić komunikaty 3 to numer komunikatu równy lub większy od WM_USER(np. WM_USER +x ale nie WM_USER - x).Nie zaniepokoi to kompilatora ale po włączeniu aplikacja na bank nie będzie nasłuchiwać, kolejny(e) parametry to komunikaty które chcemy otrzymywać (te są najważniejsze ale jest ich więcej postaram zamieścić help'a w najbliższym czasie).No tak ale co nam po sockecie który wyła komunikaty jeżeli my na nie odpowiadamy? Zaraz się za to zabierzemy:

 

char odbiorcza[250];

LRESULT CALLBACK WIindowProc(HWND okno1, UINT uMsg, WPARAM WParam, LPARAM LParam) //proces okna

{

switch (uMsg)

{

case WM_USER:

            switch (WSAGETSELECTEVENT(lParam))

{

case FD_ACCEPT:

                       

polaczony = accept(nasluchujacy,(struct sockaddr *)&sin, &rozmiar);

                       

break;

case FD_READ:

           recv(polaczony,odbiorcza,sizeof(odbiorcza),0);

break;

case FD_CONNECT:

                       

break;

case FD_WRITE:

                       

break;

}

break;

}

}

 

Długie co? Ale to już koniec programu serwera(czyli połowa całej aplikacji:)) są tu 3 funkcje WSAGETSELECTEVENT() zamienia nam lParam komunikatu WM_USER na postać komunikatów które wcześniej wybraliśmy. accept zwraca równoległy (tyle że połączony) socket, wysyła on ten sam komunikat co pierwszy, dodatkowo do niepotrzebnej pierwszemu struktury sin zapisujemy dane klienta(pamiętasz element sin_addr.s_addr? istnieją funkcje konwertujące wstecz to co się w niej znajduje(adres klienta)),kolejny to rozmiar tej struktury wcześniej zapisany. funkcja nie chce przyjąć wartości zwróconej przez sizeof() (przynajmniej mój kompilator).kolejna chyba najważniejsza to funkcja odbierająca wysłane dane z połączonego socketa(pierwszy parametr) drugi to zmienna char (chociaż można konwertować na inne typy zmiennych tylko przed innym typem zmiennej należy podać coś takiego (char *)&nazwa_zmiennej ) przedostatni parametr to rozmiar zmiennej do której zapisujemy, ostatni to dodatkowe flagi u nas 0.No to serwer gotowy przydałby się klient. a i jeszcze odpowiadanie zajmuje się tym funkcja:

 

char wysylajaca[250];

strcpy(wysylajaca,"witaj swiecie");

send(polaczony,wysylajaca,sizeof(wysylajaca),0);

 

Pierwszy parametr to socket połączony wcześniej, dalej jest to zmienna przesyłająca to co chcemy, jej rozmiar i dodatkowe flagi. Ok to na tyle

 

3. Klient

 

No i to powinno być formalnością ale nie jest. U klienta robi się prawie wszystko to samo co w serwerze z kilkoma zmianami. Zmienia się zawartość sockaddr_in,socketa, dochodzi struktura hostent  i istnieje tylko jeden socket zamiast 2.funkcje bind i funkcje listen zastępujemy connect i nie występuje tu funkcja accept jedynie recv() i send pozostają bez zmian.

zmiany w sockaddr_in

 

SOCKET klient;

klient = socket( AF_INET, SOCK_STREAM, 0 );

struct hostent *host;

host=gethostbyname("host");

 

struct sockaddr_in sin;

memset( &sin, 0, sizeof sin );

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;

sin.sin_port = htons(port);

 

connect(klient,(struct sockaddr *) &sin, sizeof(sin));

WSAAsyncSelect(klient,hWnd,WM_USER,FD_CONNECT|FD_READ|FD_WRITE|FD_ACCEPT);

 

no i tak wyglądają zmiany w tej części w .sin_addr.s_addr podajemy element stworzonej wcześniej funkcją gethostbyname() struktury hostent i funkcja connect wydaje się sercem złożonego procesu komunikacji a wystarczy jej jedynie nasz socket jego parametry i rozmiar tych parametrów. oto zmiany w komunikatach

 

char odbiorcza[250];

LRESULT CALLBACK WIindowProc(HWND okno1, UINT uMsg, WPARAM WParam, LPARAM LParam) //proces okna

{

switch (uMsg)

{

case WM_USER:

            switch (WSAGETSELECTEVENT(lParam))

{           

case FD_ACCEPT:

           

break;

case FD_READ:

                        recv(polaczony,odbiorcza,sizeof(odbiorcza),0);

break;

case FD_CONNECT:

           

break;

case FD_WRITE:

           

break;

}

}

}

 

Znika tylko accept. A funkcje send umieść gdzie ci się podoba byle tylko najpierw wystąpiło połączenie(polecam jakiś przycisk).

 

Biblioteki: WS2_32.lib

Nagłówki: winsock2.h

dll'e: brak

Przykładowy program

 

 

by:    m

Ostatnia aktualizacja ( Thursday, 01 September 2005 )
Ankieta
Jak ocenisz poziom swoich umiejętnośći?
  
Dodaj do ulubionych
Ustaw stronę startową
Ostatnio dodane
Popularne
 
top

www.winapi.org © 2003 - 2007