Johnnie Winsock Bemutatója

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.)
  • 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 :-).

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



	}

}

 

About The Author

admin

Comments are closed.