WinSock2 API. Protokol TCP.

Transkrypt

WinSock2 API. Protokol TCP.
Interfejs programowy Windows Sockets 2.
Aplikacja klient-serwer TCP Echo
Zagadnienia
• Omówienie biblioteki Winsock.
• Specyfikacja klienta tcpecho.
• Specyfikacja serwera tcpecho.
dr Zbigniew Lipiński
Instytut Matematyki i Informatyki UO
[email protected]
Interfejs programowy Windows Sockets 2
Windows Sockets jest implementacja gniazd BSD (University of California-Berkeley Sockets API).
1993 - edycja WinSock wersja 1.1.
1996 - WinSock wersja 2.0.
Windows Sockets jest interfejsem programowym warstwy transportowej modelu OSI, pozwalającym budować
aplikacje sieciowe oparte o protokoły rodziny TCP/IP.
Windows Sockets 2 definiuje interfejsy komunikacyjne do obsługi wielu standardów i usług:
• DNS, SAP, X.509,
• Quality of Service,
• transmisji w trybie multicast, multipoint.
2
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
W skład specyfikacji WinSock2 wchodzą:
• WinSock 2 API (budowa aplikacji).
• WinSock 2 Service Provider Interface , udostępnianie interfejsów WinSock 2 protokołom transportowym.
Komponenty Windows Open System Architecture (WOSA):
• WinSock Service Provider Interface (SPI), nazwy funkcji zaczynają się od ‘WSP’, np. WSPBind().
• WinSock Provider Upcall, nazwy funkcji zaczynają się od ‘WPU’, np. WPUCloseEvent().
• WSC Windows Sockets Configuration , np. WSCDeinstallProvider().
• NSP Namespace Provider, np. NSPInstallServiceClass().
Nazwy funkcji Windows Sockets 2 zaczynają się od ‘WSA’.
Przykład:
WinSock 1.1: connect()
WinSock 2.0: WSAConnect()
3
Architektura Windows Sockets 2
Źródło: MS Platform SDK.
4
Funkcje WinSock 2
Funkcje BSD:
accept()
bind()
closesocket()
connect()
getpeername()
getsockname()
getsockopt()
inet_addr()
inet_ntoa()
ioctlsocket()
listen()
ntohl(), ntohs()
recv(), recvfrom()
select()
send(), sendto()
setsockopt()
shutdown()
socket()
Funkcje Windows:
WSAAccept()
WSAAsyncGetHostByAddr(), WSAAsyncGetHostByName(),
WSAAsyncGetProtoByName(), WSAAsyncGetProtoByNumber(),
WSAAsyncGetHostByName(), WSAAsyncGetServByName(),
WSAAsyncGetServByPort(), WSAAsyncSelect(),
WSACancelAsyncRequest(), WSAAsyncGetXByY(),
WSACloseEvent(),
WSACleanup(), WSAConnect(),
WSACreateEvent(), WSADuplicateSocket(),
WSAEnumNetworkEvents(), WSAEnumProtocols(),
WSAEventSelect(), WSAGetLastError(),
WSAGetOverlappedResult(), WSAGetQOSByName(),
WSAHtonl(), WSAHtons(), WSAIoctl(), WSAJoinLeaf(),
WSANtohl(), WSANtohs(), WSAProviderConfigChange(),
WSARecv(), WSARecvFrom(), WSAResetEvent(), WSASend(),
WSASendTo(), WSASetEvent(), WSASetLastError(),
WSAGetLastError(), WSASocket(),
WSAStartup()
5
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Funkcje WinSock 2
Funkcje Windows (cd):
getservbyname(),
getservbyport(),
geth(),
gethostbyaddr(),
gethostname()
gethostbyaddr(),
getprotobyname(),
gethostname(),
get(),
gets(),
getservbyport(),
inet_addr(),
inet_ntoa()
Funkcje konwersji nazw:
WSAAddressToString(),
WSAEnumNameSpaceProviders(),
WSAGetServiceClassNameByClassId(),
WSAInstallServiceClass(),
WSALookupServiceBegin(),
WSALookupServiceEnd(),
WSALookupServiceNext(),
WSARemoveServiceClass(),
WSASetService(),
WSAStringToAddress(),
WSAAsyncGetHostByAddr(),
WSAAsyncGetHostByName(),
WSAAsyncGetProtoByName(),
WSAAsyncGetProtoByNumber(),
WSAAsyncGetServByName(),
WSAAsyncGetServByPort(),
WSACancelAsyncRequest()
WSAGetServiceClassInfo()
6
Specyfikacja struktury WSADATA
Nazwa struktury : WSADATA
Opis :
Struktura WSADATA zawiera informacje o implementacji gniazd (Windows Sockets). Struktura WSADATA jest
zadeklarowana w pliku Winsock2.h.
Aplikacja nie powinna używać atrybutów iMaxsockets, iMaxUdpDg, i lpVendorInfo struktury WSAData gdy wartość atrybutu
wVersion, po wywołaniu WSAStartup jest co najmniej 2.
Wyjaśnienie: This is because the architecture of Windows Sockets has been changed in version 2 to support multiple providers,
and WSAData no longer applies to a single vendor's stack. Two new socket options are introduced to supply provider- specific
information: SO_MAX_MSG_SIZE (replaces the iMaxUdpDg element) and PVD_CONFIG (allows any other provider-specific
configuration to occur).
Atrybuty :
wVersion - Wersja gniazd WinSock którą ma używać biblioteka Ws2_32.dll.
wHighVersion - Najwyższa wersja WinSock jaką może używać biblioteka .dll. Standardowo, wartość taka sama, jak wVersion.
szDescription - Zerem zakończony string znaków ASCI (null-terminated ASCII string) do którego Ws2_32.dll kopiuje
opis implementacji gniazd. Tekst (do 256 znaków) może być używany do opisów wiadomości.
szSystemStatus - Zakończony zerem string znaków ASCI do którego WSs2_32.dll kopiuje informacje o statusie
lub konfiguracji. Ws2_32.dll powinna używać tego atrybutu do tylko gdy informacje mogą być ważne
dla użytkowników, atrybut nie powinien być traktowany jako rozszerzenie zmiennej szDescription.
iMaxSockets - Pozostawiony dla zgodności poprzednimi wersjami gniazd. Parametr powinien być ignorowany przez
Windows Socketsv.2 i wersje późniejsze (nie ma już jednej wartości dla wszystkich dostarczycieli usług).
iMaxUdpDg - Atrybut ignorowany przez gniazda wersji 2 i następne. iMaxUdpDg pozostawiony dla zgodności z
wersją gniazd Windows Sockets 1.1. Nie powinien być używany przy budowaniu nowych aplikacji.
Dla określenia wielkości wiadomości dostarczyciela usług dla gniazda i typu gniazda aplikacje
powinny używać getsockopt aby uzyskać wartość opcji SO_MAX_MSG_SIZE.
lpVendorInfo - Atrybut ignorowany przez Windows Sockets v.2 i następne. lpVendorInfo pozostawiono dla zgodności
z wersją gniazd Windows Sockets 1.1. Dla określenia konfiguracji dostarczyciela usług dla gniazda
powinny używać getsockopt aby uzyskać wartość opcji PVD_CONFIG.
7
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Struktura WSADATA
typedef struct WSAData {
WORD
wVersion;
WORD
wHighVersion;
char
szDescription[WSADESCRIPTION_LEN+1];
char
szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR *
lpVendorInfo;
}WSADATA, *LPWSADATA;
8
Specyfikacja struktury sockaddr_in
Nazwa struktury: sockaddr_in
Opis:
Struktura sockaddr_in zawiera adres IP i numer portu odbiorcy danych.
Struktura zadeklarowana w pliku Winsock2.h (dla IPv4), ws2tcpip.h (dla IPv6).
Atrybuty:
sin_family Kod rodziny adresów TCP//IP (wartość musi być AF_INET).
sin_port
Numer portu (IP port).
sin_addr
Adres IP hosta.
sin_zero
Pole służy do uzupełniania tak, aby wielkość struktury była taka sama jak SOCKADDR.
Implementacja struktury sockaddr_in:
struct sockaddr_in {
short
unsigned short
struct in_addr
char
};
sin_family;
sin_port;
sin_addr;
sin_zero[8];
9
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury in_addr
Nazwa struktury : in_addr
Opis:
Struktura in_addr adres IP hosta. Struktura zdefiniowana w WINSOCK.H
Atrybuty :
S_un_b S_un_w S_addr -
adres hosta w formacie u_chars.
adres hosta w formacie dwóch u_shorts.
adres hosta w formacie u_long.
Implementacja struktury in_addr:
struct
in_addr
{
union {
struct
{
unsigned char
s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct
{
unsigned short s_w1, s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
};
10
Specyfikacja struktury hostent
Nazwa struktury : hostent
Opis:
Struktura jest używana przez funkcje do przechowywania informacji o hoście.
Zadeklarowana w pliku Winsock2.h
Atrybuty :
h_name – Nazwa hosta. Jeżeli jest używany system DNS (lub podobny) zmienna zawiera pełną nazwę
DNS’ową hosta FQDN (ang. Fully Qualified Domain Name).
W pliku hosts, wartość zmiennej jest drugim wpisem, po adresie IP.
h_aliases - Zerem zakończona tablica alternatywnych nazw hosta.
h_addrtype - Typ adresu.
h_length - Długość w bajtach każdego adresu.
h_addr_list - Zerem zakończona lista adresów IP hosta.
Adresy IP są zwracane w uporządkowaniu bajtów Big Endian.
Makro h_addr zastępuje h_addr_list[0] w celu zgodności ze starszymi wersjami
oprogramowania.
Przykład.
char *ServerName;
LPHOSTENT hp;
SOCKADDR_IN AdresIpSerwera;
hp = gethostbyname(ServerName);
AdresIpSerwera.sin_addr.S_addr = hp->h_addr;
11
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Implementacja struktury hostent
typedef struct hostent {
char FAR*
char FAR FAR**
short
short
char FAR FAR**
} hostent;
h_name;
h_aliases;
h_addrtype;
h_length;
h_addr_list;
12
Specyfikacja funkcji WSAStartup()
Nazwa funkcji
: WSAStartup()
Zwracana wartość: int
WSAStartup() zwraca zero gdy wywołanie funkcji zakończyło się sukcesem. W innym przypadku
zwraca następujące kody błędów:
WSASYSNOTREADY –
WSAVERNOTSUPPORTED –
WSAEINPROGRESS –
Wskazuje, że sieć lub podsieć nie jest przygotowana do transmisji danych.
Żądana wersja WinSock nie jest obsługiwana przez implementację WinSock.
Trwa operacja blokowania WinSock 1.1.
WSAEPROCLIM -
Osiągnięto granicę liczby żądań dopuszczalną przez WinSock.
WSAEFAULT -
Błędna wartość wskaźnika lpWSAData (not a valid pointer).
Argumenty:
Opis:
WORD wVersionRequested -
[in] Najwyższa obsługiwana wersja WinSock, którą nadawca
(caler) może użyć. Bajt najwyższy określa minimalną wersję,
najniższy bajt określa maksymalna wersję.
LPWSADATA lpWSAData -
[out] Wskaźnik do struktury WSADATA.
Funkcja WSAStartup() inicjuje użycie przez proces biblioteki WS2_32.DLL.
Funkcja WSAStartup() musi być pierwszą funkcja Windows Sockets wywołana przez aplikacje.
13
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji WSACleanup()
Nazwa funkcji: WSACleanup()
Zwracana wartość: int
WSACleanup() zwraca zero gdy wywołanie funkcji zakończyło się sukcesem. W innym przypadku zwraca
SOCKET_ERROR, i określony kod błędu może być uzyskany poprzez wywołanie finkcji WSAGetLastError():
WSANOTINITIALISED - Przed wywołaniem tej funkcji WSACleanup() musi być wywołana z
sukcesem funkcja WSAStartup().
WSAENETDOWN -
Awaria sieci (network subsystem has failed).
WSAEINPROGRESS - Trwa operacja blokowania WinSock 1.1 lub dostarczyciel usługi (service
provider) obsługuje komunikat zwrotny (a callback function).
Argumenty: brak
Opis:
Funkcja WSACleanup() kończy użycie biblioteki WS2_32.DLL.
14
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji socket()
Nazwa funkcji: socket()
Zwracana wartość: SOCKET
Jeżeli nie ma błędów, funkcja socket() zwraca referencje do nowego gniazda. W przeciwnym przypadku
zwraca kod INVALID_SOCKET. Kod błędu można uzyskać przez wywołanie funkcji
WSAGetLastError().
Argumenty: int af, int type, int protocol
af -
[in] Typ adresu stosu (address family specification).
type -
[in] Typ adresu dla nowych gniazd (SOCK_STREAM, SOCK_DGRAM).
protocol-
[in] Numer protokołu użytego przez gniazdo. Wartość parametru: IPPROTO_IP,
IPPROTO_TCP, 0.
Opis:
Funkcja socket() tworzy gniazdo o określonym typie (specific service provider).
Funkcja zadeklarowana w pliku winsock2.h, implementacja w pliku ws2_32.lib.
15
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji WSAGetLastError()
Nazwa funkcji: WSAGetLastError()
Zwracana wartość: int
Argumenty: brak
Opis: Funkcja WSAGetLastError() zwraca status błędu ostatniej nieudanej operacji.
16
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji htons()
Nazwa funkcji: htons()
Zwracana wartość: u_short
Funkcja htons() zwraca wartość w uporządkowaniu big-endian (TCP/IP network byte order).
Argumenty: u_short hostshort
hostshort - [in] 16-bitowa liczba w uporządkowaniu bajtów hosta (Windows: little-endian, Unix: bigendian).
Opis: Funkcja htons() konwertuje u_short z uporządkowania bajtów hosta na big-endian.
17
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji inet_addr()
Nazwa funkcji
: inet_addr()
Zwracana wartość: unsigned long
Argumenty
Opis
: const char* cp
cp - [in] Zerem zakończony string znaków reprezentujący adres IP zapisany w notacji
kropkowanej (np. 127.0.0.1).
: Funkcja inet_addr() konwertuje string zawierający adres IPv4 w wersji kropkowanej na
odpowiedni adres w strukturze IN_ADDR.
Przykład: użycie funkcji inet_addr() w strukturze sockaddr_in atrybut
sin_addr.s_addr = inet_addr(nazwa_serwera);
18
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji gethostbyname()
Nazwa funkcji
: gethostbyname()
Zwracana wartość: struct hostent* FAR
Argumenty
: const char* name
name - [in] Wskaźnik do zakończonej zerem nazwy hosta (odbiorcy danych).
Opis
: Funkcja gethostbyname() pobiera nazwę hosta z bazy hosta.
Zamiast gethostbyname() zalecane jest używanie funkcji getaddrinfo().
19
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji CopyMemory()
Nazwa funkcji
: CopyMemory()
Zwracana wartość: void
Argumenty
: PVOID Destination, const VOID* Source, SIZE_T Length
Destination - [in] Wskaźnik zawierający początkowy adres docelowego bloku danych.
Source -
[in] Wskaźnik zawierający początkowy adres źródłowego bloku danych.
Length -
[in] Wielkość kopiowanego bloku danych (wielkość liczona w bajtach).
Opis: Funkcja CopyMemory() służy do kopiowania bloków danych między obszarami pamięci.
Funkcja zadeklarowana w pliku Winbase.h, Windows.h.
20
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji connect()
Nazwa funkcji
: connect()
Zwracana wartość: int
Argumenty
: SOCKET s, const struct sockaddr* name, int namelen
s - [in] Obiekt identyfikujący niepołączone gniazdo.
name - [in] Nazwa gniazda w strukturze SOCKADDR do którego powinno być zrealizowane połączenie.
namelen - [in] Długość nazwy gniazda (liczona bajtach).
Opis
: Funkcja buduje połączenie do określonego gniazda.
21
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji send()
Nazwa funkcji
: send()
Zwracana wartość: int
Argumenty
: SOCKET s, const char* buf, int len, int flags
s
[in] Obiekt identyfikujący połączone gniazdo.
buf
[in] Bufor zawierający dane do wysłania.
len
[in] Długość danych w buforze (liczona w bajtach).
flags
[in] Wskaźnik określający typ wywołania funkcji.
Flagi:
MSG_DONTROUTE – Dane nie powinny być rutowane. WinSock
service provider może ignorować tą flagę.
MSG_OOB – Wysyła dane ‘Out-of-Band Data’ (gniazdo typu TCP, np. SOCK_STREAM).
Opis
: Funkcja send() wysyła dane do połączonego gniazda.
22
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji recv()
Nazwa funkcji
: recv()
Zwracana wartość: int
Jeśli nie ma błędów, funkcja recv() zwraca liczbę odebranych bajtów.
Jeśli połączenie zostało zamknięte (gracefully closed), zwracaną wartością jest zero.
W pozostałych przypadkach zwracana jest wartość SOCKET_ERROR.
Kod błędu można uzyskać wywołując funkcję WSAGetLastError().
Argumenty
: SOCKET s, char* buf, int len, int flags
s -
[in] Obiekt identyfikujący połączone gniazdo.
buf - [out] Bufor na przychodzące dane.
len - [in] Długość bufora (argumentu buf) w bajtach.
flags - [in] Parametr określający typ wywołania funkcji.
Opis
: Funkcja recv() odbiera dane z połączonego (connected) gniazda lub z gniazda połączonego
funkcją bind() (bound socket).
23
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji closesocket()
Nazwa funkcji
: closesocket()
Zwracana wartość: int
Argumenty
: SOCKET s
s
Opis
[in] Obiekt określający gniazdo do zamknięcia.
: Funkcja closesocket() zamyka gniazdo.
24
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji bind()
Nazwa funkcji
: bind()
Zwracana wartość: int
W przypadku błędu funkcja zwraca SOCKET_ERROR z kodem który można uzyskać wywołując
metodę WSAGetLastError(), w przeciwnym przypadku zwaraca zero.
Argumenty
: SOCKET s, const struct sockaddr* name, int namelen
s-
[in] Obiekt identyfikujący niepołączone gniazdo (unbound socket).
name -
[in] Adres IP do przypisania do gniazda (brany ze struktury SOCKADDR).
namelen - [in] Długość (w bajtach) wartości parametru name.
Opis
: Funkcja kojarzy adres lokalny hosta z gniazdem.
25
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji listen()
Nazwa funkcji
: listen()
Zwracana wartość: int
Jeśli nie ma błędów funkcja listen() zwraca zero. W pozostałych przypadkach zwracana jest wartość
SOCKET_ERROR. Kod błędu można uzyskać wywołując funkcję WSAGetLastError().
Argumenty
Opis
: SOCKET s, int backlog
s-
[in] Obiekt identyfikujący połączone (bound), nierozłączone (unconnected) gniazdo.
backlog -
[in] Maksymalna długość kolejki czekających połączeń. Jeżeli wartość parametru jest
ustawiona na SOMAXCONN, serwer ustawia wartość tego parametru na maksymalnym,
ale ‘rozsądnym’ poziomie. Nie ma standardowej procedury określania wartości tego
parametru.
: Funkcja listen() ustawia gniazdo w stan nasłuchiwania.
26
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji accept()
Nazwa funkcji
: accept()
Zwracana wartość: SOCKET
Jeżeli nie ma błędu funkcja accept() zwraca typ SOCKET. Zwrócona wartość jest uchwytem do gniazda
do którego jest tworzone połączenie.
W pozostałych przypadkach jest zwracana wartości INVALID_SOCKET. Kod błędu można uzyskać
wywołując funkcję WSAGetLastError().
Argumenty
: SOCKET s, struct sockaddr* addr, int* addrlen
s[in] Obiekt identyfikujący gniazdo, które przeszło w stan nasłuchiwania poprzez wywołanie
funkcji listen().
addr [out] Parametr opcjonalny, wskaźnik do bufora, który przechowuje adres łączącego się hosta.
Format parametru addr jest wyznaczany na podstawie wartości parametru sa_family ze
struktury SOCKADDR.
addrlen - [out] Opcjonalny wskaźnik do liczby zawierającej długość parametru addr.
27
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji htonl()
Nazwa funkcji
: htonl()
Zwracana wartość: u_long
Argumenty
: u_long hostlong
hostlong [in] 32-bitowa liczba w uporządkowaniu little endian (windows).
Opis
: Funkcja htonl() konwertuje u_long z uporządkowania little endian na big endian.
28
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji ntohs()
Nazwa funkcji
: ntons()
Zwracana wartość: u_short
Funkcja ntons() zwraca wartość w uporządkowaniu hosta.
Argumenty
Opis
: u_short netshort
netshort - [in] 16-bit liczba w uporządkowaniu big-endian (TCP/IP network byte order).
: Funkcja ntons() konwertuje liczbę u_short z uporządkowania bajtów big-endian na
uprządkowanie hosta. Aplikacja decyduje czy konwersja musi być dokonana.
Przykład:
local.sin_port = ntons((short)iPort);
29
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji inet_ntoa()
Nazwa funkcji: inet_ntoa()
Zwracana wartość: char* FAR
Jeżeli nie ma błędów inet_ntoa() zwraca wskaźnik char* do statycznego bufora zawierającego
adres w standardzie kropkowanym. W pozostałych przypadkach funkcja zwraca NULL.
Argumenty
: struct in_addr in
in - [in] Wskaźnik do struktury in_addr reprezentującej adres IP hosta.
Opis
: Funkcja inet_ntoa() konwertuje adres IPv4 na adres w formacie kropkowanym (dotted format).
30
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji CreateThread()
Nazwa funkcji : CreateThread()
Zwracana wartość: HANDLE
Funkcja zwraca uchwyt do nowego wątku.
Argumenty:
LPSECURITY_ATTRIBUTES lpThreadAttributes - [in] Wskaźnik do struktury SECURITY_ATTRIBUTES która
określa czy zwrócony uchwyt może być dziedziczony (przez proces potomny). Gdy wartość
lpThreadAttributes = NULL, uchwyt nie może być dziedziczony.
SIZE_T dwStackSize - [in] Początkowa wartość stosu liczona w bajtach. System zaokrągla wartość wielkość ‘strony’.
Jeżeli parametr ma wartość zero nowy wątek używa domyślnej wartość.
LPTHREAD_START_ROUTINE lpStartAddress - [in] Wskaźnik do funkcji aplikacji typu
LPTHREAD_START_ROUTINE która ma być wywołana przez wątek. Wskaźnik zawiera
początkową (startową) wartość adresu wątku.
LPVOID lpParameter - [in] Wskaźnik do zmiennej która ma być przekazana do wątku.
DWORD dwCreationFlags - [in] Flaga która służy do kontroli tworzenia wątku. Gdy flaga ma wartość
CREATE_SUSPENDED, wątek jest po utworzeniu zawieszony, nie zostanie uruchomiony do
czasu wywołania funkcji ResumeThread(). Gdy flaga ma zwartość zero wątek jest uruchamiany
zaraz po utworzeniu.
LPDWORD lpThreadId - [out] Wskaźnik do zmiennej zawierającej informacje o identyfikatorze wątku (thread
identifier).
31
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji CreateThread(), cd.
Wartości Arg:
Opis
lpThreadAttributes
=
NULL
dwStackSize
=
0
lpStartAddress
=
ClientThread
lpParameter
=
(LPVOID)sClient
dwCreationFlags
=
0
lpThreadId
=
&dwThreadId
: Funkcja CreateThread() tworzy wątek wykonywany wewnątrz wirtualnej przestrzeni
adresowej wywołanego procesu.
32
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji CloseHandle()
Nazwa funkcji
: CloseHandle()
Zwracana wartość: BOOL
Funkcja zwraca TRUE gdy zamknięcie uchwytu zakończyło się sukcesem.
W sytuacji błędnej funkcja zwraca zero.
Argumenty
: HANDLE hObject
hObject - [in, out] Uchwyt do otwartego obiektu.
Opis
: Funkcja CloseHandle() zamyka otwarty uchwyt obiektu.
33
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji ClientThread()
Nazwa funkcji
: ClientThread()
Zwracana wartość: DWORD WINAPI
Argumenty
: LPVOID
Implementacja funkcji ClientThread():
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock = (SOCKET)lpParam;
char
chBuff[DEFAULT_BUFFER];
int
iRet, iNumLeft, iIdx;
while(1)
{
iRet = recv(sock, chBuff, DEFAULT_BUFFER, 0);
if (iRet == 0)
return 0;
else if (iRet == SOCKET_ERROR)
{
cout << "recv() error no: " << WSAGetLastError() << endl;
return 0;
}
34
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji ClientThread()
chBuff[iRet] = '\0';
cout << "Liczba odebranych bajtów: " << chBuff << endl;
iNumLeft = iRet;
iIdx = 0;
while(iNumLeft > 0)
{
iRet = send(sock, &chBuff[iIdx], iNumLeft, 0);
if (iRet == 0)
return 0;
else if (iRet == SOCKET_ERROR)
{
cout << "send() error: " << WSAGetLastError() << endl;
return 0;
}
iNumLeft -= iRet;
iIdx += iRet;
} // koniec while(iNumLeft > 0)
}
//
koniec
while(1)
return 0;
}
35
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Protokół TCP
TCP, ang. Transmission Control Protocol. Specyfikacja RFC 793.
TCP jest protokołem warstwy transportowej modelu OSI.
Protokół TCP jest protokołem połączeniowym umożliwiającym wykrywanie błędów transmisji.
Cechy protokołu TCP:
• stosuje pozytywne potwierdzanie odbioru danych (pole ACK=1)
• ma możliwość ustalania priorytetu przesyłania segmentów
• ma możliwość kontroli i usuwania błędów (np. retransmisji niepotwierdzonych pakietów).
36
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Protokół TCP
W procesie synchronizacji 'połączenia TCP' między nadawcą (A) i odbiorcą (B) wymieniane są trzy segmenty TCP.
Uzgadnianie są wartości w polu 'Sequence number' w wysyłanych i potwierdzanych pakietach:
(1) A ----> B flaga SYN=1,
pole ‘Sequence number=X’, ISN nadawcy (A), Np.
SEQ=X=100
(2) A <---- B flagi ACK=1,
SYN=1
pole ‘Sequence number=Y’, ISN odbiorcy (B),
pole ‘Acknowledgement number=X+1’
Np. SEQ=Y=300, ACK=X+1=101
(3) A ----> B flaga ACK=1
pole ‘Acknowledgement number=Y+1,
Np. SEQ=X+1=101, ACK=Y+1=301
37
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu
Serwer TCP Echo
Nazwa projektu: tcpserver
Typ projektu: Win32 console application
Lista plików: tcpserver.cpp
Metoda kompilacji: Microsoft Visual C++ 2008.
Utworzyć projekt typu 'Win32 console application‘ w menu
(-)File-> New -> Project-> Other languages-> Visual C++ -> win32 -> Win32 console
application -> wpisać nazwę: tcpserver -> przycisk (OK) -> Okno Win32 application wizard –
tcpserver-> wybrać: Application settings -> wybrać: Empty project-> Przycisk (Finish).
Konfiguracja projektu:
(-)Project-> nazwa_projektu Properies... -> Configuration Properies-> Linker-> Input ->
Additional Dependecies, wpisać: ws2_32.lib.
Funkcjonalność:
Aby uruchomić serwer należy w linii komend (Run-> cmd) wpisać: \> tcpserver
Aby uruchomić klienta należy w linii komend (Run-> cmd) wpisać: \> tcpclient
38
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu. Serwer TCP Echo
Pliki nagłówkowe:
Funkcje programu:
Funkcje API:
Funkcja użytkownika:
winsock2.h, iostream
WSAStartup(), socket(), inet_addr(), bind(), listen(),
accept(), recv(), send(), closesocket(),
htonl(), ntohs(), inet_ntoa(),
CloseHandle(), WSAGetLastError(), WSACleanup().
CreateThread()
39
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu. Serwer TCP Echo
Zmienne programu:
#define DEFAULT_PORT
5150
#define DEFAULT_BUFFER
4096
#define DEFAULT_IP_ADDRESS "127.0.0.1"
WSADATA
SOCKET
int
wsd;
sListen, sClient;
iAddrSize;
HANDLE
DWORD
struct
hThread;
dwThreadId;
sockaddr_in
int
BOOL
char
iPort = DEFAULT_PORT;
// numer portu do nasluchiwania
bInterface = FALSE;
// nasluchiwanie na okreslonej karcie
szAddress[128] = DEFAULT_IP_ADDRESS; // adres IP karty do nasłuchowania
local, client;
40
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
(1) Sprawdzenie czy zostały otwarte biblioteki WinSock.
Czy WSAStartup(MAKEWORD(2,2), &wsd) != 0 ?
(2) Utworzenie gniazda.
sListen = socket(AF_INET, SOCK_STREAM, , IPPROTO_TCP );
(3) Inicjowanie obiektu local struktury sockaddr_in.
local.sin_addr.s_addr = inet_addr(szAddress);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);
(4) Kojarzenie adresu lokalnego hosta z gniazdem.
bind(sListen, (struct sockaddr *)&local, sizeof(local));
(5) Nasłuchiwanie na połączenie i akceptacja połączenia.
listen(sListen, 8); // 8 - maksymalna długość kolejki czekających połączeń
sClient = accept(sListen, (struct sockaddr *)&client, &iAddrSize);
(6) Utworzenie wątku dla połączenia z klientem.
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sClient, 0, &dwThreadId);
(7) Zamknięcie wątku i sesji
CloseHandle(hThread); closesocket(sListen); WSACleanup();
41
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu. Klient TCP Echo
Nazwa projektu:
Typ projektu:
Lista plików:
tcpclient
Win32 console application
tcpclient.cpp
Metoda kompilacji:
Microsoft Visual C++ 2008.
Utworzyć projekt typu 'Win32 console application‘ w menu
(-)File-> New -> Project-> Other languages-> Visual C++ -> win32 -> Win32 console application ->
wpisać nazwę: tcpclient -> przycisk (OK) -> Okno Win32 application wizard – tcpclient-> wybrać:
Application settings -> wybrać: Empty project-> Przycisk (Finish).
Konfiguracja projektu:
(-)Project-> nazwa_projektu Properies... -> Configuration Properies-> Linker-> Input -> Additional
Dependecies, wpisać: ws2_32.lib.
Funkcjonalność:
tcpclient łączy się z serwerem za pomcą protokołu TCP, wysyła wiadomość do serwer.
Serwer odpowiada, odsyłając tą samą wiadomość (odpowiedź echa).
Uruchomienie serwera: \>tcpserver
Uruchomienie klienta: \>tcpclient
42
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu. Klient TCP Echo
Pliki nagłówkowe:
winsock2.h, iostream
Funkcje programu:
Funkcje API:
WSAStartup(), WSAGetLastError(), socket(),
htons(),
inet_addr(),
gethostbyname(),
connect(), send(), recv(), closesocket(), WSACleanup().
Struktury programu:
WSDATA, sockaddr_in, hostent
43
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu. Klient TCP Echo
Zmienne programu:
#define DEFAULT_COUNT
#define DEFAULT_SERVER_PORT
#define DEFAULT_BUFFER
#define DEFAULT_MESSAGE
#define DEFAULT_SERVER
//#define DEFAULT_SERVER
WSADATA
SOCKET
char
int
1
5150
2048
”Test serwera TCP”
”127.0.0.1”
”host_name”
wsd;
sClient;
chBuffer[DEFAULT_BUFFER];
iRetSend;
struct sockaddr_in
struct hostent
server;
*host = NULL;
char
chServer[128]
= DEFAULT_SERVER,
chMessage[1024]
= DEFAULT_MESSAGE;
int
iPort = DEFAULT_SERVER_PORT;
DWORD
dwCount
= DEFAULT_COUNT;
//
//
//
//
nazwa serwera
tekst wiadomosci do wyslania
numer portu serwera do polaczenia
liczba wyslanych wiadomosci
44
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Klient TCP Echo. Struktura programu.
(1) Sprawdzenie poprawności argumentów przekazywanych do programu.
(2) Sprawdzenie czy zostały otwarte biblioteki WinSock
Czy WSAStartup(MAKEWORD(2,2), &wsd) != 0
(3) Utworzenie gniazda.
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
(4) Inicjowanie obiektu server struktury sockaddr_in.
server.sin_family = AF_INET;
server.sin_port = htons(iPort);
server.sin_addr.s_addr = inet_addr(chServer);
(5) Pobranie adresu IP serwera gdy podano jego nazwę
host = gethostbyname(chServer);
45
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Klient TCP Echo. Struktura programu.
(6) Przekazanie adresu IP serwera do obiektu server
CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length);
(7) Połączenie i sprawdzenie czy połączenie zostało utworzone
connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR
(8) Wysłanie danych na serwer, ret – liczba wysłanych bajtów.
iRet = send(sClient, chMessage, strlen(chMessage), 0);
(9) Odebranie danych z serwera.
iRet = recv(sClient, chBuffer, DEFAULT_BUFFER, 0);
(10) Zamkniecie gniazda i sesji
closesocket(sClient);
WSACleanup();
46
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
/////////////////////////////////
// TCP serwer
/////////////////////////////////
#include <winsock2.h>
#include <iostream>
using namespace std;
#define DEFAULT_SERVER_PORT
5150
#define DEFAULT_BUFFER
4096
#define DEFAULT_IP_ADDRESS "127.0.0.1"
int main()
{
WSADATA
SOCKET
int
HANDLE
DWORD
struct
int
BOOL
char
wsd;
sListen, sClient;
iAddrSize;
hThread;
dwThreadId;
sockaddr_in local, client;
iPort
= DEFAULT_SERVER_PORT; // numer portu do nasluchiwania
bInterface = FALSE;
// nasluchiwanie na okreslonej karcie
szAddress[128] = DEFAULT_IP_ADDRESS;
// adres IP karty do nasluchowania
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
cout << "WSAStartup() error" << endl;
return 0;
}
47
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
cout << "socket() error: " << WSAGetLastError() << endl;
closesocket(sListen);
WSACleanup();
return 0;
}
if (bInterface)
{
local.sin_addr.s_addr = inet_addr(szAddress);
}
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)
{
cout << "bind() error: " << WSAGetLastError() << endl;
closesocket(sListen);
WSACleanup();
return 0;
}
listen(sListen, 8);
48
while (1)
{
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client, &iAddrSize);
if (sClient == INVALID_SOCKET)
{
cout << "accept() error: " << WSAGetLastError() << endl;
closesocket(sListen);
WSACleanup();
return 0;
}
cout << "Accepted client: " <<
inet_ntoa(client.sin_addr) << ":" << ntohs(client.sin_port) << endl;
hThread = CreateThread(NULL, 0, ClientThread,(LPVOID)sClient, 0, &dwThreadId);
if (hThread == NULL)
{
cout << "CreateThread() error: " << GetLastError() << endl;
return 0;
}
CloseHandle(hThread);
} // koniec while (1)
closesocket(sListen);
WSACleanup();
return 0;
} // koniec main()
49
/////////////////////////////
// TCP Echo client
/////////////////////////////
#include <winsock2.h>
#include <iostream>
using namespace std;
#define DEFAULT_COUNT
#define DEFAULT_SERVER_PORT
#define DEFAULT_BUFFER
#define DEFAULT_MESSAGE
#define DEFAULT_SERVER
// #define DEFAULT_SERVER
1
5150
2048
"Test serwera TCP"
"127.0.0.1"
"builder" //mozna wpisac nazwe hosta
int main() {
WSADATA
SOCKET
char
int
wsd;
sClient;
chBuffer[DEFAULT_BUFFER];
iRetSend;
struct sockaddr_in server;
struct hostent
*host = NULL;
char chServer[128] = DEFAULT_SERVER,
chMessage[1024] =
DEFAULT_MESSAGE;
int
iPort
=
DEFAULT_SERVER_PORT;
DWORD dwCount
=
DEFAULT_COUNT;
// nazwa serwera
// tekst wiadomosci do wyslania na serwer
// numer portu serwera do polaczenia
// liczba wyslanych wiadomosci
50
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
cout << "WSAStartup() error" << endl;
return 0;
}
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
cout << "socket() error no: " << WSAGetLastError() << endl;
return 0;
}
server.sin_family = AF_INET;
server.sin_port = htons(iPort);
server.sin_addr.s_addr = inet_addr(chServer);
if (server.sin_addr.s_addr == INADDR_NONE)
{
host = gethostbyname(chServer);
if (host == NULL)
{
cout << "Unable to resolve: " << chServer << endl;
return 0;
}
CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length);
}
if (connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
cout << "connect() error no: " << WSAGetLastError()<< endl;
return 0;
}
51
for(unsigned int i=0; i<dwCount; i++)
{
iRetSend = send(sClient, chMessage, strlen(chMessage), 0);
if (iRetSend == 0)
return 0;
else if (iRetSend == SOCKET_ERROR)
{
cout << "send() error no: " << WSAGetLastError() << endl;
return 0;
}
cout << "Wyslano bajtow: " << iRetSend << endl;
iRetSend = recv(sClient, chBuffer, DEFAULT_BUFFER, 0);
if (iRetSend == 0)
return 0;
else if (iRetSend == SOCKET_ERROR)
{
cout << "recv() error no: " << WSAGetLastError() << endl;
return 0;
}
chBuffer[iRetSend] = '\0';
cout << "Odebrano " << iRetSend << " bajtow. Msg: " << chBuffer << endl;
} // end for()
closesocket(sClient);
WSACleanup();
return 0;
} // end main()
52

Podobne dokumenty