Sieci Komputerowe, inf sc w5, Inicjalizacja Winsock


Gniazda w MS Windows. Biblioteka Winsock.

Inicjalizacja Winsock.

Niezbędne pliki nagłówkowe to Winsock.h (starsza wersja biblioteki Winsock - 1.1) lub Winsock2.h (wersja Winsock 2.2). Należy dołączyć plik biblioteczny ws2_32.lib.

W Windows CE oraz Windows 95 dostępna jest wersja 1.1. W nowszych wersjach Windows 95 oraz w Windows 98, Windows Me, Windows NT 4.0, Windows 2000 dostępna jest wersja 2.2 biblioteki.

Przed wywołaniem dowolnej funkcji Winsock należy załadować poprawną wersję biblioteki Winsock. Funkcją, która to realizuje jest WSAStartup:

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData)

Pierwszy parametr określa wersję biblioteki Winsock, którą chcemy załadować (obecnie najnowszą wersją jest 2.2). Dla wersji 2.2 należy podać wartość 0x0202 lub skorzystać z makra MAKEWORD(2,2). Starszy bajt określa numer podwersji, młodszy określa główny numer wersji.

Drugim parametrem (typ LPWSADATA) jest wskaźnik do struktury WSAData. Struktura ta zawiera informacje o załadowanej wersji Winsock. Wskaźnik do odpowiednio uzupełnionej struktury jest zwracany przez funkcję WSAStartup.

Opis struktury WSAData:

typedef struct WSAData {

WORD wVersion; // wersja Winsock, której chce używać funkcja wywołująca

WORD wHighVersion; // najwyższa wersja Winsock obsługiwana przez

// załadowaną bibliotekę

char szDescription[WSADESCRIPTION_LEN+1]; // opis tekstowy

// załadowanej biblioteki

char szSystemStatus[WSASYS_STATUS_LEN+1]; // opis stanu i

// konfiguracji

unsigned short iMaxSockets; // maks. liczba gniazd - pole ignorowane w Winsock

// powyżej wersji 2

unsigned short iMaxUdpDg; // maks. rozmiar datagramu UDP - pole ignorowane w

// Winsock powyżej wersji 2

char FAR * lpVendorInfo; // info. o sprzedawcy - pole ignorowane w Winsock

// powyżej wersji 2

} WSADATA, FAR * LPWSADATA;

W Win32 FAR jest ignorowane!

Po zakończeniu korzystania z biblioteki Winsock bależy wywołać funkcję WSACleanup(), która usunie bibliotekę z pamięci i zwolni zasoby.

Otwieranie gniazd.

W Win32 gniazdo nie jest identyfikowane przez deskryptor taki jak deskryptor pliku. Utworzony jest typ SOCKET (w Winsock2.h i Winsock.h) - jako UINT_PTR (zdefiniowane w basetsd.h jako unsigned int o rozmiarze takim jak wskaźnik).

Większość nazw rozbudowanych funkcji dotyczących gniazd w Winsock 2.2 rozpoczyna się od liter WSA. Tego przedrostka nie ma większość funkcji z Winsock 1.1 (za wyjątkiem np. WSAStartup i WSACleanup). Winsock 2.2 umożliwia stosowanie podstawowych funkcji z Winsock 1.1 (bez przedrostka WSA).

Gniazda można otworzyć za pomocą dwóch funkcji: WSASocket (Winsock 2.2) i socket (Winsock 1.1).

Podstawowa wersja:

SOCKET socket (

int sf,

int type,

int protocol

);

Rozbudowana wersja:

SOCKET WSASocket (

int af, //rodzina adresów - dla TCP i UDP jest to AF_INET

int type, // typ protokołu np. SOCK_STREAM dla TCP, SOCK_DGRAM dla UDP

int protocol, // IPPROTO_IP dla TCP, IPPROTO_UDP dla UDP

LPWSAPROTOCOL_INFO lpProtocolInfo, // zaawansowane użycie

GROUP g, // nie używane

DWORD dwFlags // zaawansowane użycie

);

Adresowanie gniazd.

struct sockaddr_in

{

short sin_family; // AF_INET

u_short sin_port; // numer portu w sieciowej kolejności bajtów

struct in_addr sin_addr; // adres IP 32 bity w sieciowej kolejności

char sin_zero[8]; // dla zgodności rozmiaru struktury z sockaddr.

}

Numery portów:

0-1023 zarezerwowane dla usług powszechnie znanych,

1024-49151 do wykorzystania przez programy

49152-65535 porty dynamiczne i do wykorzystania przez programy.

Konwersja wartości wielobajtowych z kolejności sieciowej na kolejność komputera i odwrotnie.

u_long htonl(u_long hostlong);

u_short htons(u_short hostshort);

u_long ntohl (u_long netlong);

u_short ntohs(u_short netshort);

Są również odpowiedniki bardziej rozbudowane z przedrostkami WSA (patrz Pomoc).

Funkcja konwertująca „kropkowy” adres IP (np. 149.155.144.32) na adres zapisany na 4 bajtach w kolejności sieciowej:

unsigned long inet_addr(

const char FAR *cp

);

cp jest wskaźnikiem do ciągu znaków zakończonego `\0'.

W Winsock dostępne są funkcje gethostbyname oraz gethostbyaddr (analogiczne jak w systemie Unix).

struct hostent

{

char FAR * h_name;

char FAR * FAR * h_aliases;

short h_addrtype;

short h_length;

char FAR * FAR * h_addr_list;

}

struct hostent FAR * gethostbyname (

coonst char FAR * name

);

name wskazuje na tekstową nazwę komputera.

Podstawowe funkcje (analogiczne jak w systemie Unix).

int bind (

SOCKET s,

const struct sockaddr FAR * name,

int namelen

)

int listen (

SOCKET s,

int backlog

);

SOCKET accept(

SOCKET s,

struct sockaddr FAR * addr,

int FAR * addlen

);

(jest też funkcja WSAAccept)

int connect(

SOCKET s,

const struct sockaddr FAR * name,

int namelen

);

(jest też funkcja WSAConnect)

Transmisja danych.

Wysyłanie danych

int send(

SOCKET s, // gniazdo

const char FAR * buf, // bufor przechowujący wysyłane znaki

int len, // liczba znaków w buforze

int flags // na ogół 0

);

Przykład wysyłania danych:

char sendbuff[2048]

int nBytes = 2048,

nLeft, // ile bajtów zostało do wysłania

indx; // indeks wskazujący początek miejsca w buforze do wysłania nie przesłanych

jeszcze danych

// Tu powinno być wypełnienie bufora danymi

nLeft = nBytes;

indx = 0;

while (nLeft > 0)

{

ret = send (s, &sendbuff[indx], nLeft, 0);

if ( ret == SOCKET_ERROR )

{

// Błąd

}

nLeft -= ret;

indx += ret;

}

Odbiór danych (znaczenie parametrów podobne do send).

int recv(

SOCKET s,

char FAR * buf,

int len,

int flags

);

Zakończenie połączenia.

int shutdown(

SOCKET s,

int how

);

how może przyjąć wartości: SD_RECEIVE, SD_SEND, SD_BOTH. Np. dla SD_SEND nie będą możliwe dalsze wywołania funkcji wysyłających (ale wszystkie dane oczekujące na wysłanie zostaną wysłane, oraz po potwierdzeniu odbioru wygenerowany pakiet FIN).

int closesocket( SOCKET s );

Jest to zamknięcie gniazda i zwolnienie deskryptora. Usunięte będą też dane oczekujące w kolejce.

Przykład zastosowania - serwer i klient echa.

---------------------------------------------------------------------------------------------------------

SERVER

// Program Server.c

//

// Opis:

// Prosta aplikacja serwera TCP, akceptująca nachodzące

// połączenia klientów. Po ustanowieniu połączenia

// uruchamiany jest wątek odczytujący dane przesłane przez

// klienta i odsyłający je z powrotem (o ile opcja odsyłania

// nie jest wyłączona).

//

//

// Opcje wiersza poleceń:

// server [-p:x] [-i:IP] [-o]

// -p:x Numer nasłuchującego portu

// -i:str Nasłuchujący interfejs (nr IP)

// -o Tylko odbiór, bez odsyłania

//

#include <winsock2.h>

#include <stdio.h>

#include <stdlib.h>

#define DEFAULT_PORT 5250

#define DEFAULT_BUFFER 4096

int iPort = DEFAULT_PORT; // Port nasłuchujący klientów

BOOL bInterface = FALSE, // Nasłuchujący interfejs

bRecvOnly = FALSE; // Tylko odbiór, bez odsyłania

char szAddress[128]; // Interfejs nasłuchujący klientów

//

// Funkcja: usage

//

// Opis:

// Wydruk informacji o działaniu programu

//

void usage()

{

printf("użycie: server [-p:x] [-i:IP] [-o]\n\n");

printf(" -p:x Numer nasluchujacego portu \n");

printf(" -i:str Nasluchujacy interfejs \n");

printf(" -o Tylko odbior, bez odsylania\n\n");

ExitProcess(1);

}

//

// Funkcja: ValidateArgs

//

// Opis:

// Analiza argumentów wiersza poleceń i ustalenie wartości

// niektórych zmiennych globalnych, decydujących o wykonaniu

// określonych czynności.

//

void ValidateArgs(int argc, char **argv)

{

int i;

for(i = 1; i < argc; i++)

{

if ((argv[i][0] == '-') || (argv[i][0] == '/'))

{

switch (tolower(argv[i][1]))

{

case 'p':

iPort = atoi(&argv[i][3]);

break;

case 'i':

bInterface = TRUE;

if (strlen(argv[i]) > 3)

strcpy(szAddress, &argv[i][3]);

break;

case 'o':

bRecvOnly = TRUE;

break;

default:

usage();

break;

}

}

}

}

//

// Funkcja: ClientThread

//

// Opis:

// Ta funkcja jest wywoływana w postaci wątku obsługującego

// dane połączenie klienta. Przekazany parametr jest uchwytem

// gniazda zwróconym przez wywołanie funkcji accept(). Ta

// funkcja czyta dane nadesłane przez klienta i odsyła je

// z powrotem.

//

DWORD WINAPI ClientThread(LPVOID lpParam)

{

SOCKET sock=(SOCKET)lpParam;

char szBuff[DEFAULT_BUFFER];

int ret,

nLeft,

idx;

while(1)

{

// Wykonanie blokującej funkcji recv ()

//

ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);

if (ret == 0) // Zamknięcie uzgodnione

break;

else if (ret == SOCKET_ERROR)

{

printf("Funkcja recv() zakonczona bledem: %d\n",

WSAGetLastError());

break;

}

szBuff[ret] = '\0';

printf("ODBIOR: '%s'\n", szBuff);

//

// Odesłanie danych (jeżeli wybrano tę opcję).

//

if (!bRecvOnly)

{

nLeft = ret;

idx = 0;

//

// Sprawdzenie, czy zapisaliśmy wszystkie dane

//

while(nLeft > 0)

{

ret = send(sock, &szBuff[idx], nLeft, 0);

if (ret == 0)

break;

else if (ret == SOCKET_ERROR)

{

printf("Funkcja send() zakonczona"

" bledem: %d\n",

WSAGetLastError());

break;

}

nLeft -= ret;

idx += ret;

}

}

}

return 0;

}

//

// Funkcja: main

//

// Opis:

// Wątek główny. Inicjacja interfejsu Winsock, analiza

// argumentów wiersza poleceń, utworzenie nasłuchującego

// gniazda, związanie go z adresem lokalnym i oczekiwanie

// na połączenia klientów.

//

int main(int argc, char **argv)

{

WSADATA wsd;

SOCKET sListen,

sClient;

int iAddrSize;

HANDLE hThread;

DWORD dwThreadId;

struct sockaddr_in local,

client;

ValidateArgs(argc, argv);

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

{

printf("Nie mozna wczytac biblioteki Winsock!\n");

return 1;

}

// Utworzenie nasłuchującego gniazda

//

sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

if (sListen == SOCKET_ERROR)

{

printf("Funckja socket() zakonczona bledem: %d\n",

WSAGetLastError());

return 1;

}

// Wybór lokalnego interfejsu, z którym zostanie

// związane gniazdo

//

if (bInterface)

{

local.sin_addr.s_addr = inet_addr(szAddress);

if (local.sin_addr.s_addr == INADDR_NONE)

usage();

}

else

local.sin_addr.s_addr = htonl(INADDR_ANY);

local.sin_family = AF_INET;

local.sin_port = htons(iPort);

if (bind(sListen, (struct sockaddr *)&local,

sizeof(local)) == SOCKET_ERROR)

{

printf("Funkcja bind() zakonczona bledem: %d\n",

WSAGetLastError());

return 1;

}

listen(sListen, 8);

//

// Oczekiwanie na żądania klientów w ciągłej pętli. Po

// wykryciu próby połączenia, utworzenie wątku i przekazanie

// jego uchwytu.

//

while (1)

{

iAddrSize = sizeof(client);

sClient = accept(sListen, (struct sockaddr *)&client,

&iAddrSize);

if (sClient == INVALID_SOCKET)

{

printf("Funkcja accept() zakonczona bledem: %d\n",

WSAGetLastError());

break;

}

printf("Zaakceptowano klienta: %s:%d\n",

inet_ntoa(client.sin_addr), ntohs(client.sin_port));

hThread = CreateThread(NULL, 0, ClientThread,

(LPVOID)sClient, 0, &dwThreadId);

if (hThread == NULL)

{

printf("Funkcja CreateThread() zakończona błędem: %d\n",

GetLastError());

break;

}

CloseHandle(hThread);

}

closesocket(sListen);

WSACleanup();

return 0;

}

---------------------------------------------------------------------------------------------------------

CLIENT

// Program Client.c

//

// Opis:

// Przykładowa aplikacja klienta powtarzającego. Klient ten łączy

// się z serwerem TCP, wysyła dane i odczytuje dane odesłane

// przez serwer.

//

// Kompilacja:

// cl -o Client Client.c ws2_32.lib

//

// Opcje wiersza poleceń:

// client [-p:x] [-s:IP] [-n:x] [-o]

// -p:x Numer odległego portu

// -s:IP Adres IP serwera lub nazwa węzła

// -n:x Liczba wysyłanych wiadomości

// -o Tylko wysyłanie, bez odbioru

//

#include <winsock2.h>

#include <stdio.h>

#include <stdlib.h>

#define DEFAULT_COUNT 3

#define DEFAULT_PORT 5250

#define DEFAULT_BUFFER 2048

#define DEFAULT_MESSAGE "To jest test klienta echa"

char szServer[128]="gandalf", // Serwer, z którym się łączymy

szMessage[1024]; // Wysyłana wiadomość

int iPort = DEFAULT_PORT; // Numer portu serwera

DWORD dwCount = DEFAULT_COUNT; // Ilość nadań wiadomości

BOOL bSendOnly = FALSE; // Tylko nadawanie, bez odbioru

//

// Funkcja: usage:

//

// Opis:

// Wydruk informacji o działaniu programu

//

void usage()

{

printf("uzycie: client [-p:x] [-s:IP] [-n:x] [-o]\n\n");

printf(" -p:x Numer odleglego portu\n");

printf(" -s:IP Adres IP serwera lub nazwa stacji\n");

printf(" -n:x Ilosc nadan wiadomosci\n");

printf(" -o Tylko nadawanie, bez odbioru\n");

ExitProcess(1);

}

//

// Funkcja: ValidateArgs

//

// Opis:

// Analiza argumentów wiersza poleceń i ustalenie wartości

// niektórych znaczników globalnych, decydujących o wykonaniu

// określonych czynności.

//

void ValidateArgs(int argc, char **argv)

{

int i;

for(i = 1; i < argc; i++)

{

if ((argv[i][0] == '-') || (argv[i][0] == '/'))

{

switch (argv[i][1])

{

case 'p': // Odległy port

if (strlen(argv[i]) > 3)

iPort = atoi(&argv[i][3]);

break;

case 's': // Serwer

if (strlen(argv[i]) > 3)

strcpy(szServer, &argv[i][3]);

break;

case 'n': // Liczba nadań wiadomości

if (strlen(argv[i]) > 3)

dwCount = atol(&argv[i][3]);

break;

case 'o': // Tylko nadawanie, bez odbioru

bSendOnly = TRUE;

break;

default:

usage();

break;

}

}

}

}

//

// Funkcja: main

//

// Opis:

// Wątek główny. Inicjacja interfejsu Winsock, analiza

// argumentów wiersza poleceń, tworzenie gniazda, połączenie

// z serwerem, a następnie wysyłanie i odbieranie danych.

//

int main(int argc, char **argv)

{

WSADATA wsd;

SOCKET sClient;

char szBuffer[DEFAULT_BUFFER];

int ret,

i;

struct sockaddr_in server;

struct hostent *host = NULL;

// Analiza wiersza poleceń i wczytanie biblioteki Winsock

//

ValidateArgs(argc, argv);

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

{

printf("Nie mozna wczytac biblioteki Winsock!\n");

return 1;

}

strcpy(szMessage, DEFAULT_MESSAGE);

//

// Utworzenie gniazda i próba połączenia się z serwerem

//

sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (sClient == INVALID_SOCKET)

{

printf("Funkcja socket() zakonczona bledem: %d\n",

WSAGetLastError());

return 1;

}

server.sin_family = AF_INET;

server.sin_port = htons(iPort);

server.sin_addr.s_addr = inet_addr(szServer);

//

// Jeżeli podany adres serwera nie ma postaci

// "aaa.bbb.ccc.ddd" jest to wówczas nazwa węzła,

// więc należy ją odwzorować

//

//

if (server.sin_addr.s_addr == INADDR_NONE)

{

host = gethostbyname(szServer);

if (host == NULL)

{

printf("Nie udalo sie znalezc"

" serwera: %s\n", szServer);

return 1;

}

CopyMemory(&server.sin_addr, host->h_addr_list[0],

host->h_length);

}

if (connect(sClient, (struct sockaddr *)&server,

sizeof(server)) == SOCKET_ERROR)

{

printf("Funkcja connect() zakonczona bledem: %d\n",

WSAGetLastError());

return 1;

}

// Wysyłanie i odbiór danych

//

for(i = 0; i < dwCount; i++)

{

ret = send(sClient, szMessage, strlen(szMessage), 0);

if (ret == 0)

break;

else if (ret == SOCKET_ERROR)

{

printf("Funkcja send() zakonczona bledem: %d\n",

WSAGetLastError());

break;

}

printf("Wyslano %d bajtow\n", ret);

if (!bSendOnly)

{

ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0);

if (ret == 0) // Zamknięcie uzgodnione

break;

else if (ret == SOCKET_ERROR)

{

printf("Funkcja recv() zakonczona bledem: %d\n",

WSAGetLastError());

break;

}

szBuffer[ret] = '\0';

printf("ODBIOR [%d bajtow]: '%s'\n", ret, szBuffer);

}

}

closesocket(sClient);

WSACleanup();

return 0;

}

Sieci komputerowe wykład 5.

1



Wyszukiwarka

Podobne podstrony:
Sieci Komputerowe, inf sc w2, Przez sieć komputerową rozumiemy wszystko to, co umożliwia komputerom
Sieci Komputerowe, inf sc w3, Przez sieć komputerową rozumiemy wszystko to, co umożliwia komputerom
Sieci Komputerowe, inf sc w1, Przez sieć komputerową rozumiemy wszystko to, co umożliwia komputerom
Sieci Komputerowe, Wykład9, Inicjalizacja Winsock
lab6 SK I8X2S1 ZADANIE, inf, IV sem, Sieci komputerowe, Laborki
SK ćw4B 2h Konfigurowanie sieci WLAN v3, inf, IV sem, Sieci komputerowe, Laborki
9 Sieci komputerowe II
Sieci komputerowe 7
sieci komputerowe 2
TS Rozlegle sieci komputerowe
Sieci komputerowe fizyka informatyka

więcej podobnych podstron