Original page: http://johnnie.jerrata.com/winsocktutorial/
Ha szándékosan megérkezett a Winsock bemutató, amit valószínűleg az ötletet a saját alkalmazások kommunikálnak az interneten keresztül, mint lenyűgöző kilátás, mint én. Vagy talán valaki megtalálta a kilátásba szintén érdekes, és akkor már megbízott hozza ezt az álom valósággá válik. Mindkét esetben a Winsock hálózati szolgáltatás és ez a bemutató segít a célok elérésében a kereskedelmi vállalkozás, egyszerűen feltárása birodalmában műsorok személyes használatra, vagy valami a kettő között.
Itt van, amit lesz, amely:
- Létrehozása Socket: Adott egy kis sereg a hálózati funkciók tudjuk építeni a programot, hogy türelmesen várja a bejövő kapcsolatokat? (Igen, tudjuk.)
- Így a saját kapcsolatok: Mivel még néhány funkció, lehet létrehozni egy programot, amely sikeresen összeköti lehallgató szerver? (Igen, tudjuk.)
- Küldése és fogadása: Miután elértük aktív kapcsolat, hogyan használjuk az adatcserét a két program között? (Te találtad ki-send () és recv () ).
- Leállás és aszinkron socket: Hogyan tudjuk növelni a hatékonyságot a kód végrehajtása révén különböző hálózati rendszer? (Mi bajlódnia ablakunk eljárás egy kicsit)
- További útmutatók és linkek: Milyen források vannak túl is ez a bemutató? Emelem 3 hogy tartsa meg elfoglalt egy darabig (miután emésztett én bemutató, természetesen :-).
- Comments & kritikák: Itt a lehetőség, hogy értékelje a bemutató, kérdéseket feltenni, vagy hozzászóláshoz.
Bár lehet, hogy alig várja, hogy elérje, hogy a félelmetes pontot, ahol az alkalmazás sikeresen való első kapcsolat, legyen tisztában a fogalmak mögött a kódot. Próbálja meg elkerülni egyszerűen manipulálni a megadott kódot, hogy megfeleljen a közvetlen szükségletek, és helyette azonosítani a követelményeket az alkalmazás és csak akkor hajtsa végre, amit úgy tűnik, hogy a legjobb megoldás. Ez elég a Zen Szoftverfejlesztés tanácsot most; nézzük meg néhány hálózati programozás …
Nyugodtan le a teljes útmutatót kódot hirdetések. Ne feledje, hogy minden kódot mutatja be ezt a bemutató össze kell kapcsolni a Winsock könyvtár , általában wsock32.lib vagy valami hasonló nevű. Így, amikor kódot pontosan bemutatott bemutató saját IDE (Dev-C ++, a Microsoft VC ++, C ++ Builder, stb), úgy dönt, hogy építsenek egy Windows-projekt egy WinMain (), hogy elkerüljék a hibákat. |
Létrehozása Socket
Alkalmazások szervizelése kívül gépek hívják kiszolgálók. Szerver alkalmazások hallgatni az ügyfelek által inicializálása egy vagy több hallgat foglalat. Amikor egy kliens csatlakozik egy ilyen hallgat aljzatok, a szerver megkapja az értesítést a Winsock, elfogadja a csatlakozást, és elkezdi a feladást és lehallgatott üzeneteket és az új kliens. Talán a legegyszerűbb módszer, amellyel a szerverek kezelik több ügyfelet, hogy kapsz egy új szálat minden kliens kapcsolatot. Ez a szerver modell a leggyakrabban használ blokkoló foglalatok, amelyek ideiglenes szüneteltetésére, hogy megvárja a bejövő adatokat, egy új kapcsolatot, és más hálózati eseményeket. Először is nézzük azonosítani néhány struktúrák akkor kell inicializálni egy blokkoló socket:
- WSADATA: Ez a struktúra lekérdezni az operációs rendszer verzióját Winsock kódunk van szükség. Egy alkalmazás kéri WSAStartup () elindítani a helyes Winsock DLL.
- SOCKET: Egy objektum (sőt, ez határozza meg, mint egy u_int, előjel nélküli egész szám, és winsock.h- jó tudni Smalltalk bulikon) által használt alkalmazások tárolására foglalat fogantyút.
- SOCKADDR_IN : Egy alkalmazás használja ezt a struktúrát, hogy meghatározza, hogy egy aljzat kell működtetni. SOCKADDR_IN mezőket tartalmaz egy IP-címet és a port számát:
struct sockaddr_in { short sin_family; // Protocol type u_short sin_port; // Port number of socket struct in_addr sin_addr; // IP address char sin_zero[8]; // Unused }; |
Az első mező a protokoll típusa, amely általában AF_INET (TCP / IP). Ennek Socket nem érintett a hálózati címet a gépet, amelyen lakik, Megnyerő automatikusan kiosztja az IP-címet és a port számát hallgatja aljzatok a létrehozás.
Majd elkészítjük első hallgatási szerver a fenti struktúrák és egy kis sereg a hálózati funkciók:
#include <windows.h> #include <winsock.h> #include <stdio.h> #define NETWORK_ERROR -1 #define NETWORK_OK 0 void ReportError(int, const char *); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) { WORD sockVersion; WSADATA wsaData; int nret; sockVersion = MAKEWORD(1, 1); // We’d like Winsock version 1.1 // We begin by initializing Winsock WSAStartup(sockVersion, &wsaData); // Next, create the listening socket SOCKET listeningSocket; listeningSocket = socket(AF_INET, // Go over TCP/IP SOCK_STREAM, // This is a stream-oriented socket IPPROTO_TCP); // Use TCP rather than UDP if (listeningSocket == INVALID_SOCKET) { nret = WSAGetLastError(); // Get a more detailed error ReportError(nret, “socket()”); // Report the error with our custom function WSACleanup(); // Shutdown Winsock return NETWORK_ERROR; // Return an error value } // Use a SOCKADDR_IN struct to fill in address information SOCKADDR_IN serverInfo; serverInfo.sin_family = AF_INET; serverInfo.sin_addr.s_addr = INADDR_ANY; // Since this socket is listening for connections, // any local address will do serverInfo.sin_port = htons(8888); // Convert integer 8888 to network-byte order // and insert into the port field // Bind the socket to our local server address nret = bind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)); if (nret == SOCKET_ERROR) { nret = WSAGetLastError(); ReportError(nret, “bind()”); WSACleanup(); return NETWORK_ERROR; } // Make the socket listen nret = listen(listeningSocket, 10); // Up to 10 connections may wait at any // one time to be accept()’ed if (nret == SOCKET_ERROR) { nret = WSAGetLastError(); ReportError(nret, “listen()”); WSACleanup(); return NETWORK_ERROR; } // Wait for a client SOCKET theClient; theClient = accept(listeningSocket, NULL, // Optionally, address of a SOCKADDR_IN struct NULL); // Optionally, address of variable containing // sizeof ( struct SOCKADDR_IN ) if (theClient == INVALID_SOCKET) { nret = WSAGetLastError(); ReportError(nret, “accept()”); WSACleanup(); return NETWORK_ERROR; } // Send and receive from the client, and finally, closesocket(theClient); closesocket(listeningSocket); // Shutdown Winsock WSACleanup(); return NETWORK_OK; } void ReportError(int errorCode, const char *whichFunc) { char errorMsg[92]; // Declare a buffer to hold // the generated error message ZeroMemory(errorMsg, 92); // Automatically NULL-terminate the string // The following line copies the phrase, whichFunc string, and integer errorCode into the buffer sprintf(errorMsg, “Call to %s returned error %d!”, (char *)whichFunc, errorCode); MessageBox(NULL, errorMsg, “socketIndication”, MB_OK); } |
Egy dolog, amit azonnal észre a kód a mennyiségű erőfeszítést helyezték hibajavítás. Amikor hiba lép fel, a kód szerez egy adott hibakód WSAGetLastError (), és az eredményt eltárolja nret. A hibakód ezután elküldésre kerül egy sor nevének feltüntetésével a sikertelen funkciót egy egyedi funkció elemzi ReportError (). Van egy hibaüzenet van kialakítva, és kimutatták, hogy a felhasználó egy hívás MessageBox (), amely része a standard WinAPI. Például volt hallgatni () nem egy hiba kódja 10093 (definíció szerint WSANOTINITIALISED), a kész hiba húr lenne „Call hallgatni () által visszaadott hiba 10093!”. Te, a körültekintő fejlesztő, aztán felnéz a kódot, és fedezze fel, hogy hiba történt, mert egy sikeres hívás WSAStartup () még nem került sor.
Aleksandar Pavlov bővült ez ReportError () a leírását tartalmazza, körülbelül egy tucat közös socket hibát. Segítségével a továbbfejlesztett változata, akkor már nem kell megkeresni a mi a kód jelenti, és a programunk lesz sokkal inkább felhasználóbarát, nagyon kevés erőfeszítést az Ön részéről. |
Idetartoznak azok Meghatározza a NETWORK_ERROR és NETWORK_OK.Ezek hasznosak lehetnek, amikor ellenőrzi a visszatérési értéke a saját hálózati funkciókat. Ha a funkció vissza a következő értékek egyikét, a hívó függvény is egy egyszerű egyenlőség vizsgálat tárt fel hibákat: if (myNetworkingFunction () == NETWORK_ERROR) {…}. A hívó függvény is megkaphatja egy adott kódot WSAGetLastError () és kezeli a hibát kell. Végső soron, végrehajtásában egy jó hibaelhárító program most takarít meg több napos vagy hetes fejlesztési idő, akkor azonnal tudja, hogy miért a programot nem sikerült.
Amellett, hogy visszatérnek egy új ügyfél kapcsolat, fogadja () segítségével a kiszolgáló kivonat információt a kliens helyett módszerekkel igénylő extra funkció kéri, vagy időt (ami válhat az a probléma, játék szerver, ahol a sebességet a elfogadom hurok különösen kritikai). Ahhoz, hogy kihasználják ezt a funkciót, át a címét egy sockaddr_in struct öntött egy sockaddr mutatót, azaz a (LPSOCKADDR) & aSockaddrInStructure. Továbbá, állapítsa egész szám változó, az értéket az int a sizeof a sockaddr struct, és adja át a címét a egész szám, mint a harmadik paraméter. Ha címadatok vissza kell, miután a függvény hívás hosszától paraméter jelen kell lennie.
jdarnold figyelmeztet minket, hogy nem hisznek az MSDN vonatkozó dokumentációkat harmadik paraméter: „Az MSDN docs jelenti, hogy nem kell átadni a addrlen, hogy ez csak egy opcionális kimeneti paraméter, de tévednek. Bejövő azt mondja, hogy hány bájt a sockaddr puffert és kimenő [Megnyerő] kitölti hány [Megnyerő] használt. Ha át nullát len, [Megnyerő] nem nyúl a puffer.” |
Ez nem sok a szerver, mert vár csak egy felhasználó a csatlakozást, majd azonnal bontja, de a legalapvetőbb design. Csak tisztázni a dolgokat, egy hívás, hogy WSAStartup () egy WORD meghatározza, hogy milyen verziójú a betölteni kívánt (ebben az esetben ez 1.1) és a címét egy WSADATA szerkezetét. Ezután fogjuk fedezni, hogyan lehet csatlakozni más számítógépekhez.
Így a saját kapcsolatok
Létrehozása csatlajozó valaki más használja a legtöbb azonos funkciók, kivéve a HOSTENT struct:
- HOSTENT: A szerkezet szokta mondani az aljzat, amelyhez a számítógép és a csatlakozóhoz. Ezek a szerkezetek általában jelennek LPHOSTENT változók, amelyek csupán mutatókat HOSTENT szerkezetek. Ahogy kód Windows, akkor általában úgy találják, hogy az adattípus előzi LP jelenti, hogy a típus valójában egy mutató a „bázis” típusú (például LPCSTR egy mutató a C húr, vagy más néven char *).
Nos, nézzük rögtön a kódot:
#include <windows.h> #include <winsock.h> #include <stdio.h> #define NETWORK_ERROR -1 #define NETWORK_OK 0 void ReportError(int, const char *); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) { WORD sockVersion; WSADATA wsaData; int nret; sockVersion = MAKEWORD(1, 1); // Initialize Winsock as before WSAStartup(sockVersion, &wsaData); // Store information about the server LPHOSTENT hostEntry; hostEntry = gethostbyname(“www.yahoo.com”); // Specifying the server by its name; // another option: gethostbyaddr() if (!hostEntry) { nret = WSAGetLastError(); ReportError(nret, “gethostbyname()”); // Report the error as before WSACleanup(); return NETWORK_ERROR; } // Create the socket SOCKET theSocket; theSocket = socket(AF_INET, // Go over TCP/IP SOCK_STREAM, // This is a stream-oriented socket IPPROTO_TCP); // Use TCP rather than UDP if (theSocket == INVALID_SOCKET) { nret = WSAGetLastError(); ReportError(nret, “socket()”); WSACleanup(); return NETWORK_ERROR; } // Fill a SOCKADDR_IN struct with address information SOCKADDR_IN serverInfo; serverInfo.sin_family = AF_INET; // At this point, we’ve successfully retrieved vital information about the server, // including its hostname, aliases, and IP addresses. Wait; how could a single // computer have multiple addresses, and exactly what is the following line doing? // See the explanation below. serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list); serverInfo.sin_port = htons(80); // Change to network-byte order and // insert into port field // Connect to the server nret = connect(theSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)); if (nret == SOCKET_ERROR) { nret = WSAGetLastError(); ReportError(nret, “connect()”); WSACleanup(); return NETWORK_ERROR; } // Successfully connected! // Send/receive, then cleanup: closesocket(theSocket); WSACleanup(); } void ReportError(int errorCode, const char *whichFunc) { char errorMsg[92]; // Declare a buffer to hold // the generated error message ZeroMemory(errorMsg, 92); // Automatically NULL-terminate the string // The following line copies the phrase, whichFunc string, and integer errorCode into the buffer sprintf(errorMsg, “Call to %s returned error %d!”, (char *)whichFunc, errorCode); MessageBox(NULL, errorMsg, “socketIndication”, MB_OK); } |
A legbonyolultabb sorban a lista a következő:
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list); |
hajt végre, ezért több művelet-egyikük viszonylag rejtett egyszerre. Nézzük meg, hogy eltekintve lépésről lépésre:
A h_addr_list tagja HOSTENT struct alapvetően definiáljuk char ** h_addr_list, amely egy sor húrok, vagy char * ‘s. gethostbyname () azonosított és másolja az összes ismert címét szerver ezt a listát. Azonban nem a koncepció több címet alapvetően értelme? Ami azt illeti, igen. A számítógép, sőt, van egy sor általános hálózati címeket. Az Internet-cím lehet 205.182.67.96, a LAN-cím lehet 10.0.0.2 és minden számítógépen, amelyre a Windows telepítve van természetesen van egy „loopback” címe 127.0.0.1, a számítógép által használt utal maga a helyi hálózaton. Ugyanez az elv érvényesül a birodalmában az Internet címek vagy IP-k, ezért a lista van szükség, nem pedig tárhelyet egy címet. Megjegyezzük, hogy a preferált cím, azaz a leginkább elérhető címet, mindig másolja az első eleme a listán, majd a második előnyös vagy más címeket.
Mi * hostEntry-> h_addr_list csinál? Lehet, hogy úgy gondolják, a tisztelet operátor (*) van használatban legyen egyetlen címet a listán. Azonban mivel nem egy meghatározott indexet, a dereference működése automatikusan feltárja az első, előnyös címet. Ez különösen részén egyenértékű * hostEntry-> h_addr_list [0], amely garantálja, hogy létezik, mivel a szerver kell legalább egy címet.
Ezután a char * által visszaadott visszahivatkozási művelet öntik egy in_addr * vagy LPIN_ADDR. Végül egy másik tisztelettel műveletet végzünk, hogy visszatérjen a in_addr struct által említett mutatót, ami csak tartani egy címet. A kapott in_addr struct ezután hozzárendelve serverInfo.sin_addr. Az ezt követő connect () veszi az egy címet, mint a paraméter, amikor képez kapcsolatot a szerverrel.
Ha a szerver IP címe ismert, érvényes HOSTENT kaphatunk használata révén gethostbyaddr () (szemben a gethostbyname (), amelyet a korábban lista):
LPHOSTENT hostEntry;
in_addr iaHost;
iaHost.s_addr = inet_addr(“204.52.135.52”);
hostEntry = gethostbyaddr((const char *)&iaHost, sizeof(struct in_addr), AF_INET);
if (!hostEntry) { // Handle accordingly } |
Ebben az esetben a inet_addr () arra használjuk, hogy másolni egy string, amely az IP-címet közvetlenül egy in_addr struct. Ezután a címét a struct öntünk const char * által előírt gethostbyaddr (). Mindkét módszer nevezzük megoldása a szerver címét, mivel Megnyerő visszatér teljes címe bejegyzések részleges információkat.
Néhány további megjegyzés: 80-as portot használunk egyszerűen azért, mert az Internet weboldal transzfer megtörténik a porton. Ha volt, hogy küldjön egy string egy web szerver kér egy adott fájlt, és megkísérli, hogy valamit kap vissza, ha volna egy nagyon egyszerű webböngésző. Persze, hogy a string tartalmaznia kell egy teljes HTTP parancsot. Nagyon jó, hogy tudjuk hallgatni, és csatlakozni más számítógépekhez, de a kommunikáció magában foglalja küldésére és fogadására.
Küldése és fogadása
Küldés kezelnek, kényelmesen elég, a send () függvényt:
int send(
SOCKET s, const char * FAR buf, int len, int flags ); |
Alapvetően akkor másolja amit akart egy tárolóba, és használja a send () függvény egy csatlakoztatott csatlakozó, hogy az adatok megy a másik vége:
char buffer[256]; // Declaring a buffer on the stack char *buffer = new char[256]; // or on the heap
ZeroMemory(buffer, 256); strcpy(buffer, “Pretend this is important data.”);
nret = send(theSocket, buffer, strlen(buffer), // Note that this specifies the length of the string; not // the size of the entire buffer 0); // Most often is zero, but see MSDN for other options
delete [] buffer; // If and only if the heap declaration was used
if (nret == SOCKET_ERROR) { // Get a specific code // Handle accordingly return NETWORK_ERROR; } else { // nret contains the number of bytes sent } |
Fogadása, ugyanaz a folyamat, visszafelé:
char buffer[256]; // On the stack char *buffer = new char[256]; // or on the heap
nret = recv(theSocket, buffer, 256, // Complete size of buffer 0);
delete [] buffer; // Manipulate buffer, then delete if and only if // buffer was allocated on heap
if (nret == SOCKET_ERROR) { // Get a specific code // Handle accordingly return NETWORK_ERROR; } else { // nret contains the number of bytes received } |
Milyen érdekes megjegyezni, hogy van egy gomb az eszköztár a Microsoft Outlook jelölt „Send/Fog.” Is „vételi” rövidítve „Fog” egyszerűen, hogy biztosítsák a gomb jobbra néz, vagy ez egy programozó szokás a gépelési recv () számos alkalommal? Képezik a saját összeesküvés-elméletek (ismét jó Smalltalk bulikon).
Ez az, ahol belefutottam egy kis probléma írásakor a saját WinSock programokat. Csak a recv () jó, ha pontosan tudja, hogy mennyi adatot fog kapni (mint például a játék, ahol az első bájt lehet egy parancsot, és a következő bájt egy paraméter, stb), de ha don tudom, mit csinálsz? Ha a kívánt adatokat átvevő megszűnik egy újsor karakter (egy gyakori probléma a Java kliens beszél C szerverek), akkor írj egy ReadLine () függvényt, hogy rögzítse minden fel, hogy a karakter. Itt van, amit használni:
char * readLine() { vector theVector; char buffer; int bytesReceived; while (true) { bytesReceived = recv(theSocket, &buffer, 1, 0); if (bytesReceived <= 0) return NULL; if (buffer == '\n') { char *pChar = new char[theVector.size() + 1]; memset(pChar, 0, theVector.size() + 1); for (int f = 0; f < theVector.size(); f++) pChar[f] = theVector[f]; return pChar; } else { theVector.push_back(buffer); } } } |
Egy vektort alkalmazunk elrendezése helyett egy, mert annak tárolási helyet növelhető automatikusan, hogy megfeleljen a vonal hosszát. Ha recv () függvény hibát jelez (bytesReceived kisebb, mint nulla), NULL vissza. Mivel ez egy lehetőség, telefonálási funkciókat biztosítania kell, hogy a húr visszaadott ReadLine () érvényes használat előtt. Belül a hurok, egy char érkezik az aljzatból, és, ha nem egy sor karakter, hozzáadjuk a vektor. Ha ez egy újsor karaktert, a tartalom a vektor másolása egy C string, és visszatért. A string nyilvánított egy char nagyobb, mint a vektor és memset () ‘Ted nullára, hogy a visszaadott sor automatikusan NULL megszűnik. Befejezés húrok NULL megakadályozza szokatlan hibákat, és általában jó programozási gyakorlat.
Sem mutatja be ezt ügyesen javított változata, amely támogatja a felbukkanó törlések és a képesség, hogy módosítsa az új sor karaktert egyszerűen:
// Code originally written by Nor. Modified slightly to // support the MessageBox() API, make logic more readable, // align spacing, and add comments. Posted with permission. #define backKey '\b' // To disable backspaces, #define backKey NULL #define newLine '\n' #define endStr '\0' char *readLine(SOCKET s) { vector theVector; char buffer; char *pChar; int bytesReceived; while (true) { bytesReceived = recv(s, &buffer, 1, 0); if (bytesReceived <= 0) { MessageBox(NULL, "recv() returned nothing.", "socketIndication", MB_OK); return NULL; } switch (buffer) { case backKey: // Handle backspace if (theVector.size() > 0) theVector.pop_back(); break; case endStr: // If end of string char reached, case newLine: // or if end of line char reached, pChar = new char[theVector.size() + 1]; memset(pChar, 0, theVector.size() + 1); for (int f = 0; f < theVector.size(); f++) pChar[f] = theVector[f]; return pChar; break; default: // Any regular char theVector.push_back(buffer); break; } } } |
A nem-blokkoló és aszinkron aljzatok
Eddig a pontig már beszélünk blokkoló foglalatok, ahol egy funkció, mint elfogadni () korlátlan ideig várakozik a felhasználó csatlakozni. Egy nem-blokkoló socket azonnal visszatér, amikor azt mondtuk, hogy tegyen valamit, akár a sikeres eredmény, hiba, vagy semmi (jelezve, hogy lesz valami, hogy megkapja később). A hátránya az ilyen típusú, hogy neked kell manuálisan lekérdezni az aljzatba, hátha eredményeként jött el minden funkció hívja. Akkor át egy sor aljzatok a select () függvény, hogy melyek készen állnak az olvasás, írás, vagy visszatértek a hibákat.
Funkciók aszinkron socket is vissza azonnal, de megadhat egy üzenetet küld az ablakon eljárást, amikor egy meghatározott esemény történt. Például lehetőség van a foglalat Levél SOCKET_GOTMSG üzenetet, amikor kap valamit. Általában ez okos, hogy ellenőrizze a hibákat (nehézkes, de szükség szerint), ha kap egy üzenetet, hogy megakadályozzák socket okoz felesleges problémákat később. Először nézzük meg, bizonyos funkciók fogjuk használni, hogy hozzon létre egy aszinkron socket:
- int WSAAsyncSelect (SOCKET s, HWND hwnd, unsigned int wMsg, hosszú Levent)
Ez a funkció használható azonosítani a socket aszinkron és társult egy üzenetet is. s az aljzat, akivel együtt dolgozik. hwnd a fogantyút az ablakhoz, hogy megkapja az üzenetet, ha az aljzat generál egy eseményt. wMsg az üzenetet szeretne küldeni az ablakot eljárás (erre példa a SOCKET_GOTMSG üzenet fent). Levent paraméter egyet vagy többet vesz zászlók, hogy elmondja az aljzatba, hogy mely események az üzenet elküldéséhez. Néhány ezek a zászlók:- FD_READ: Socket készen áll az adatok fogadására
- FD_WRITE: Socket készen áll az adatok
- FD_ACCEPT: használt szerverek, ez az üzenet jelzi a felhasználó csatlakozik
- FD_CONNECT: Használt kliens alkalmazás, ez az üzenet azt mondja, az aljzat csatlakoztatva
- FD_CLOSE: A foglalat nemrég bezárt
- WSAGETSELECTERROR (lParam lParam)
Meghatározza, hogy a socket hibát adott vissza. Technikailag ez nem egy függvény, hanem egy makrót (akkor tényleg generál Smalltalk bulikon ezzel a kis factoid).
- WSAGETSELECTEVENT (lParam lParam)
Egy másik hasznos makro meghatározott winsock2.h van WSAGETSELECTEVENT (), amelyet használnak, hogy pontosan mi a foglalat tette.
Nos, nézzük létrehozott aszinkron socket:
// Kezdjük létrehozásával zászló, hogy a Windows fogja használni, hogy lépjen kapcsolatba velünk, ha valami történik, #define THERE_WAS_A_SOCKET_EVENT WM_USER + 100 // WM_USER egy bázis egyéni üzeneteket |
// Valahol a inicializáló kódot után CreateWindow (), hívjuk WSAAsyncSelect () WSAAsyncSelect (theSocket, hwnd, THERE_WAS_A_SOCKET_EVENT, FD_READ | FD_WRITE | FD_CONNECT | …);
// Ez fordítja: Windows, várjuk a THERE_WAS_A_SOCKET_EVENT zászlót, hogy én // korábban meghatározott valahányszor adatait olvasni (FD_READ), vagy ha szabad vagyok, hogy adatokat küldjön // (FD_WRITE), vagy amikor már sikeresen kapcsolódott másnak (FD_CONNECT), vagy ha … stb. |
LRESULT WinAPI TheWindowProcedure (HWND hwnd, UINT msg, wParam wParam, lParam lParam) { kapcsolót (MSG) { ügy THERE_WAS_A_SOCKET_EVENT: if (WSAGETSELECTERROR (lParam)) {// Ha hiba történt, closesocket (theSocket); WSACleanup (); // leállítás Megnyerő visszatérés NETWORK_ERROR; } kapcsolót (WSAGETSELECTEVENT (lParam)) {// Mi történt pontosan? ügy FD_READ: // Adatok fogadása szünet; ügy FD_WRITE: // Write data szünet; ügy FD_CONNECT: // Csak csatlakoztatott kiszolgáló szünet; ügy ... // Ugyanaz a telepítést más zászlók szünet; } szünet; // másik esetben kimutatások logika, amely a többi Windows-üzenetek } } |