Martin Úbl

Osobní stránky

KIV/UPS

Sockety na MS Windows

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.

Odlišnosti

Zavírání socketu

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);
Časovaný select

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);