Autor: Georg 'Black' Wicherski
In diesem Tutorial dreht sich alles um das Erstellen eines Server Sockets, einen Client Socket haben wir ja bereits in dem Grundlagen Tutorial programmiert. Unser Server wird eine Zahl (float) von einem Client bekommen, dieser 'verarbeiten' und dann zurücksenden.
Die Anfänge eines Server Sockets liegen wie die eines Client Sockets in der Funktion socket(…). Nachdem man mit socket(…) einen Socket erstellt hat, sollte man diesen sinnvollerweise mit bind(…) an eine feste Adresse binden, auf die er später 'hören' soll, denn sonst können die Clients ja nicht sinnvoll connecten.
bind(…) bekommt als ersten Parameter wie alle anderen Funktionen auch unseren Socket. Als zweiten Parameter übergeben wir einen konformen Pointer auf eine SOCKADDR_IN, als dritten Parameter die Größe dieser Struktur.
#include <windows.h> #include <winsock.h> #pragma comment(lib, "ws2_32.lib") int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char * szCommandLine, int nShowMode) { { WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wdData; WSAStartup(wVersionRequested, &wdData); } { SOCKET sckSocket; SOCKADDR_IN addrServer; float flNumber; addrServer.sin_addr.s_addr = INADDR_ANY; // listen on all IPs associated with this computer addrServer.sin_port = htons(61473); // bind to port 61473 addrServer.sin_family = AF_INET; if((sckSocket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) return 256; if(bind(sckSocket, (SOCKADRR *) &addrServer, sizeof(addrServer)) == SOCKET_ERROR) return 254;
Das Element sin_addr des structs addrServer scheint auf den ersten Blick keinen Sinn zu machen, dient aber dazu, auf Computern die mehrere IPs besitzen (z.B. Internet Server) eventuell nur eine IP zu belegen. INADDR_ANY bedeutet hier, dass der Socket auf alle IPs reagiert.
Jetzt müssen wir den Socket in den sogenannt listen-Modus bringen. Ein Socket im listen-Modus lauscht auf Verbindungsanfragen von Clients.
Wir bringen unseren Socket mit der Funktion listen(…) in diesen Modus. Die Funktion bekommt zwei Parameter: Unseren Socket und die Größe der Backloop, die bestimmt, wie viele Clients sich der Socket maximal auf einmal merken kann. Achtung, dieser Wert bestimmt nicht das Maximum aller Verbindungen. Meistens ist 4 für kleine und 16 für große Projekte ausreichend.
if(listen(sckSocket, 4) == SOCKET_ERROR) return 253;
Um jetzt an einen Client dranzukommen, gibt es die Funktion accept(…), diese erhält mal wieder unseren Server-Socket und falls wir wissen wollen, wer sich da verbindet noch zwei Pointer, für die man aber in den meisten Fällen 0 übergeben kann.
Damit wir nicht nur einen Client akzeptieren packen wir das ganze noch in eine schöne Endlossschleife. In dieser Schleife müssen wir auch unsere anderen Clients versorgen oder für jeden Client einen Thread starten.
while(true) { SOCKET sckClient = accept(sckSocket, 0, 0); if(sckClient != INVALID_SOCKET) HandleClient(sckClient); } return 0; }
Die Funktion HandleClient(…) dient hier nur als Platzhalter, normalerwiese würde ich an dieser Stelle einen Thread erstellen, dem ich als Parameter unseren neuen sckClient übergeben würde.
Das war's auch schon wieder für heute, morgen seht ihr dann, wie Peter Lustig von einer fleischfressenden Pflanze gefressen wird und daraufhin einen UDP Socket erstellt.
Dieses Tutorial stammt aus der ehemaligen Sammlung des resourcecode.de und konnte dank der freundlichen Zustimmung des Autors in das thewall-Wiki übertragen werden.