Pozn.: tato stránka pojednává o nutném minimu pro použití BSD socketů ve Windows, nikoliv o samotném rozhraní WinSocks, které se od BSD API výrazně liší.
Rozhraní BSD socketů je na OS MS Windows shodné, jako na systémech ostatních. Je ale pár dodatečných úkonů, které je nutné učinit, aby vše fungovalo jak má. Existuje také
pár drobných rozdílů, na které si je třeba dát pozor.
Ve Windows je implementace socketů přítomna v knihovně WinSocks (verze 2). V první řadě je potřeba použít správné hlavičky, konkrétně winsock2.h
a ws2tcpip.h
#include <winsock2.h>
#include <ws2tcpip.h>
Dále je třeba přilinkovat knihovnu Ws2_32.lib
. To uděláte buď v nastavení projektu ve Vašem IDE, v příkazové řádce (např. -lWs2_32
pro gcc/Windows),
a nebo v kódu můžete použít direktivu preprocesoru:
#pragma comment(lib, "Ws2_32.lib")
Narozdíl od jiných systémů, MS Windows dělá v rozhraní rozdíl mezi socketem a souborem, byť část funkcí sdílejí. I proto je nutné všechny sockety na Windows
typovat na typ SOCKET
. Pro přenositelnost mezi systémy můžete udělat typový alias:
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
Pak lze snadno všude používat typ socket_t
.
Windows vyžaduje inicializaci knihovny WinSocks funkcí WSAStartup
:
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
return -1;
}
Po ukončení práce se sockety (tedy typicky na konci programu při jeho korektním ukončování) Windows vyžaduje deinicializaci v podobě volání WSACleanup
:
if (WSACleanup() != 0) {
return -1;
}
WinSocks si interně udržuje čítač inicializací - pokud tedy máte sdílený kód, který by mohl vyžadovat socketové funkce nezávisle na sobě (a tedy volat WSAStartup
a WSACleanup
v různých scope), není třeba zavádět vyšší logiku. První kdo volá WSAStartup
knihovnu inicializuje, poslední kdo volá WSACleanup
knihovnu deinicializuje.
Na cvičení jsme sockety klasicky zavírali voláním funkce close()
s parametrem socketu. MS Windows tím, že odlišuje soubory od socketů vyžaduje i jiné volání.
Pro zavření socketu na Windows volejte funkci closesocket()
se stejným parametrem.
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);
// ...
closesocket(server_socket);
Posledním parametrem volání funkce select()
může být struktura s hodnotami, které označují časový interval zablokování. Na některých verzích MS Windows je nutné
vyplnit atribut tv_usec
alespoň na hodnotu 1.
struct timeval_t timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 1;
int result = select(FD_SETSIZE, &sockets, NULL, NULL, &timeout);