mail@pastecode.io avatar
a year ago
12 kB
# Define _ WIN32_WINNT 0x0400 # include <windows. h> # include <cstdio> # include "InitSocket. h "CInitSock initSock; // The structure of the SOCKET object has been initialized before entering the main function. The s and event members must be placed in the initial position typedefstruct _ SOCKET_OBJ {SOCKET s; // socket HANDLE event; // socket-related event HANDLE sockaddr_in addrRemote; // client address _ SOCKET_OBJ * pNext; // next address} SOCKET_OBJ, * PSOCKET_OBJ; // thread object. Each thread is responsible for managing up to 64 connected typedefstruct _ THREAD_OBJ {HANDLE events [WSA_MAXIMUM_WAIT_EVENTS]; // record the current Handle of the event object to be waited by the thread, event object table int nSocketCount; // record the number of sockets processed by the current thread PSOCKET_OBJ pSockHeader; // list of socket objects processed by the current thread, pSockHeader points to the header PSOCKET_OBJ pSockTail; // pSockTail points to the end of the table CRITICAL_SECTION cs; // key code segment variable, in order to synchronize the access to this structure _ THREAD_OBJ * pNext; // points to the next THREAD_OBJ object, in order to connect to a table} THREAD_OBJ, * PTHREAD_OBJ; // SOCKET object processing function PSOCKET_OBJ GetSocketObj (SOCKET s); // apply for a SOCKET object, initialize its member void FreeSocketObj (PSOCKET_OBJ pSocket); // release a socket object // thread object Processing Function PTHREAD_OBJ GetThreadObj (); void FreeThreadObj (PTHREAD_OBJ pThread); // recreate the events array void RebuildArray (PTHREAD_OBJ pThread) of the thread object ); // insert a socket BOOL InsertSocketObj (PTHREAD_OBJ pThead, PSOCKET_OBJ pSocket) into the socket list of a thread ); // assign a socket object to a idle thread to process void AssignToFreeThread (PSOCKET_OBJ pSocket); // remove a socket object void RemoveSocketObj (PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket); // The Working thread is responsible for processing the customer's I/O Request DWORD WINAPI SeverThread (LPVOID lpParam); // process real I/OBOOL HandleIO (PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket ); // The FindSocketObj function searches for the corresponding socket object PSOCKET_OBJ FindSocketObj (PTHREAD_OBJ pThread, int nIndex) based on the index of the event object in the events array; // global variable PTHREAD_OBJ g_pThreadList; // point to the header CRITICAL_SECTION g_cs of the thread object list; // synchronize access to global variables // LONG g_nTotalConnections maintained by the main thread; // total number of connections, that is, processed, including disconnected LONG g_nCurrentConnections; // current connection count // main function int main (void) {U SHORT nPort = 4567; SOCKET sListen = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in sin; sin. sin_family = AF_INET; sin. sin_port = htons (nPort); sin. sin_addr.s_addr = INADDR_ANY; // All interface addresses if (SOCKET_ERROR = bind (sListen, (sockaddr *) & sin, sizeof (sin) {printf ("Failed bind () \ n "); return-1;} listen (sListen, 200); // creates a listener event object and associates it with the listener socket WSAEVENT event = WSACreateEvent (); WSAEventSelect (sListen, event, FD_ACCEPT | FD_CLOSE); // select the listening socket for the event, and select the connection and exit event InitializeCriticalSection (& g_cs); // process the client connection request and print the status information while (TRUE) {int nRet = WaitForSingleObject (event, 5*1000); if (nRet = WAIT_FAILED) {printf ("Failed WaitForSingleObject () \ n"); break ;} else if (nRet = WSA_WAIT_TIMEOUT) // periodically displays status information {printf ("\ n"); printf ("Total Connections: % d \ n", g_nTotalConnections ); printf ("Current Connections: % d \ n", g_nCurrentConnections );} Else // a connection event occurs, and the listener event is triggered {ResetEvent (event); // process all pending connections cyclically while (TRUE) {sockaddr_in si; int nLen = sizeof (si); SOCKET sNew = accept (sListen, (sockaddr *) & si, & nLen); // because it has been selected by the event, therefore, if (SOCKET_ERROR = sNew) {break;} PSOCKET_OBJ pSocket = GetSocketObj (sNew); pSocket-> addrRemote = si; WSAEventSelect (pSocket-> s, pSocket-> event, FD_READ | FD_CLOSE | FD_WRITE); // Add a new socket object and the corresponding event AssignToFreeThread (pSocket) ;}} DeleteCriticalSection (& g_cs); return 0 ;}// apply for a SOCKET object and initialize its member PSOCKET_OBJ GetSocketObj (SOCKET s) {PSOCKET_OBJ pSocket = (PSOCKET_OBJ) globalAlloc (GPTR, sizeof (SOCKET_OBJ); // The global heap and local heap are not distinguished. HeapAllocif (pSocket! = NULL) {pSocket-> s = s; pSocket-> event = WSACreateEvent ();} return pSocket;} // release the socket object void FreeSocketObj (PSOCKET_OBJ pSocket) {CloseHandle (pSocket-> event); if (pSocket-> s! = INVALID_SOCKET) {closesocket (pSocket-> s);} GlobalFree (pSocket);} // get a thread object PTHREAD_OBJ GetThreadObj () {PTHREAD_OBJ pThread = (PTHREAD_OBJ) GlobalAlloc (GPTR, sizeof (THREAD_OBJ); if (pThread! = NULL) {InitializeCriticalSection (& pThread-> cs); // creates an event object to indicate that the handle array of the thread needs to be rebuilt, pThread-> events [0] = WSACreateEvent (); // Add the newly applied thread object to the list EnterCriticalSection (& g_cs); pThread-> pNext = g_pThreadList; // insert it to the linked list of thread objects g_pThreadList = pThread; LeaveCriticalSection (& g_cs) ;}return pThread ;}// release a thread object void FreeThreadObj (PTHREAD_OBJ pThread) {// find the object indicated by pThread in the thread object list. If found, remove EnterCriticalSection (& g_cs); PTHREAD _ OBJ p = g_pThreadList; if (p = pThread) // if you want to delete the header node {g_pThreadList = p-> pNext;} else {while (p! = NULL & p-> pNext! = PThread) {p = p-> pNext;} if (p! = NULL) {// p is the first of pThread, that is, "p-> pNext = pThread" p-> pNext = pThread-> pNext ;}} leaveCriticalSection (& g_cs); // release the resource CloseHandle (pThread-> events [0]); DeleteCriticalSection (& pThread-> cs); GlobalFree (pThread );} // re-create the events array of the thread object. because event objects are stored in arrays, and socket objects are stored in linked lists, there will be inconsistent mappings when a socket object is closed. void RebuildArray (PTHREAD_OBJ pThread) {EnterCriticalSection (& pThread-> cs); // to synchronously listen to the connection thread's access to this thread object PSOCKET_OBJ pSocket = pThre Ad-> pSockHeader; int n = 1; // write from 1st, and 0th are used to indicate that the while (pSocket! = NULL) {pThread-> events [n] = pSocket-> event; pSocket = pSocket-> pNext; n ++;} LeaveCriticalSection (& pThread-> cs );} // insert a socket BOOL InsertSocketObj (PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket) to the socket list of a thread {BOOL bRet = FALSE; EnterCriticalSection (& pThread-> cs ); if (pThread-> nSocketCount <WSA_MAXIMUM_WAIT_EVENTS-1) // The maximum number of event objects that a thread can wait for {if (NULL = pThread-> pSockHeader) // The socket list of threads is null {pThread-> pSockHeader = pThrea D-> pSockTail = pSocket;} else {pThread-> pSockTail-> pNext = pSocket; pThread-> pSockTail = pSocket;} pThread-> nSocketCount ++; bRet = TRUE ;} leaveCriticalSection (& pThread-> cs); // if (bRet) {InterlockedIncrement (& g_nTotalConnections ); // InterlockedIncrement (& g_nCurrentConnections);} return bRet;} // schedule a socket object to a idle thread for void AssignToFreeThread (PSOCKET_OBJ pSocket) {pSocket-> pNext = NUL L; EnterCriticalSection (& g_cs); PTHREAD_OBJ pThread = g_pThreadList; // The thread object linked list header // tries to insert it into the existing thread while (pThread! = NULL) {if (InsertSocketObj (pThread, pSocket) {break;} pThread = pThread-> pNext;} // No idle thread, create a new thread for this socket if (NULL = pThread) {pThread = GetThreadObj (); InsertSocketObj (pThread, pSocket); CreateThread (NULL, 0, SeverThread, pThread, 0, NULL); // beginthreadex is used. A thread object corresponds to a thread, and the thread parameter is the thread object corresponding to the thread} LeaveCriticalSection (& g_cs ); // instruct the new thread to reconstruct the handle array WSASetEvent (pThread-> events [0]);} // remove a socket object void RemoveSocketObj (PT HREAD_OBJ pThread, PSOCKET_OBJ pSocket) {EnterCriticalSection (& pThread-> cs); // query the specified socket object in the socket Object List, remove PSOCKET_OBJ pTest = pThread-> pSockHeader; if (pTest = pSocket) // Delete the header node {if (pThread-> pSockHeader = pThread-> pSockTail) // there is only one node {pThread-> pSockTail = pThread-> pSockHeader = pTest-> pNext ;} else // There are not only one head node {pThread-> pSockHeader = pTest-> pNext ;}} else {while (pTest! = NULL & pTest-> pNext! = PSocket) {pTest = pTest-> pNext;} if (pTest! = NULL) {if (pThread-> pSockTail = pSocket) // Delete the End Node {pThread-> pSockTail = pTest ;} pTest-> pNext = pSocket-> pNext;} pThread-> nSocketCount --; LeaveCriticalSection (& pThread-> cs); WSASetEvent (pThread-> events [0]); // indicates that the thread re-creates the handle array InterlockedDecrement (& g_nCurrentConnections); // indicates that a connection is interrupted} // The Working thread is responsible for processing the customer's I/O Request DWORD WINAPI SeverThread (LPVOID lpParam) {// get the pointer PTHREAD_OBJ pThread = (PTHREAD_OBJ) lpParam; whi Le (TRUE) {// wait for the network event int nIndex = WSAWaitForMultipleEvents (pThread-> nSocketCount + 1, pThread-> events, FALSE, WSA_INFINITE, FALSE); nIndex = nIndex-WSA_WAIT_EVENT_0; // is the index triggered here the lowest? // Check whether the event object for (int I = nIndex; I <pThread-> nSocketCount + 1; ++ I) {nIndex = WSAWaitForMultipleEvents (1, & pThread-> events [I], TRUE, 1000, FALSE ); // only wait for a single event object if (nIndex = WSA_WAIT_FAILED | nIndex = WSA_WAIT_TIMEOUT) {continue;} else // if an event triggers {if (0 = I) // events [0] has been triggered. re-create the Array {RebuildArray (pThread); // if no client I/O has to be processed, then this thread exits if (0 = pThread-> nSocketCount) {FreeThreadObj (pThread); re Turn 0;} WSAResetEvent (pThread-> events [0]); // reset event correspondence} else // process network events {// find the corresponding socket Object Pointer, call HandleIO to process network events. index I is used for search, so we need to recreate the array before. PSOCKET_OBJ pSocket = (PSOCKET_OBJ) FindSocketObj (pThread, I); if (pSocket! = NULL) {if (! HandleIO (pThread, pSocket) // when HandleIO returns FALSE, it indicates that the socket is closed or an error occurs. Although the array is rebuilt {RebuildArray (pThread );}} else {printf ("Unable to find socket object \ n") ;}}} return 0 ;} // The FindSocketObj function searches for the corresponding socket object PSOCKET_OBJ FindSocketObj (PTHREAD_OBJ pThread, int nIndex) based on the index of the event object in the events array) // nIndex starts from 1 {// query PSOCKET_OBJ pSocket = pThread-> pSockHeader in the socket list; while (-- nIndex) // reverse query reason {if (NULL = pSocket) {return NULL;} pSocket = p Socket-> pNext;} return pSocket;} // process the real I/OBOOL HandleIO (PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket) {// obtain the specific network event WSANETWORKEVENTS event; WSAEnumNetworkEvents (pSocket-> s, pSocket-> event, & event); // binds the socket to a network event. do {if (event. lNetworkEvents & FD_READ) {if (event. iErrorCode [FD_READ_BIT] = 0) {char szText [256]; int nRecv = recv (pSocket-> s, szText, sizeof (szText), 0); // sizeof? If (nRecv> 0) {szText [nRecv] = '\ 0'; printf ("received data: % s \ n", szText );}} else {break;} if (event. lNetworkEvents & FD_CLOSE) // You must reduce the number of connections here. You cannot/* else if */. This is the case in the book. As a result, the connection {if (event. iErrorCode [FD_CLOSE_BIT] = 0) {printf ("close a connection \ n"); break;} else {printf ("An error occurred while closing the connection \ n "); break;} if (event. lNetworkEvents & FD_WRITE) // else if {if (event. iErrorCode [FD_WRITE_BIT] = 0) {} else {break;} return TRUE;} while (FALSE); // If the socket is disabled or an error occurs, the program will go here to execute RemoveSocketObj (pThread, pSocket); FreeSocketObj (pSocket); return FALSE ;}