This is the 24th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

Event selection model

Objectives and Requirements

1. Understand the application scenarios of the event selection model;

2. Master the communication process of event selection model;

3. Master the code implementation of event selection model;

4. Understand the improvement method of event selection model: order and increase the number of clients.

Server side:

1, including network header file network library

#include <WinSock2.h>

#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")

#pragma warning(disable:4996);
Copy the code

2. Open the network library

int nRes = WSAStartup(wdVersion, &wdScokMsg); if (0 ! = nRes) {switch (nRes) {case WSASYSNOTREADY: printf(" 下 载 "... \n"); break; case WSAVERNOTSUPPORTED: break; case WSAEINPROGRESS: break; case WSAEPROCLIM: break; case WSAEFAULT: break; } return 0; }Copy the code

3. Verify the version

if (2 ! = HIBYTE(wdScokMsg.wVersion) || 2 ! = LOBYTE(wdscokmsg.wversion)) {printf(" Version problem! \n"); WSACleanup(); return 0; }Copy the code

4. Create a SOCKET

SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == socketServer) { int err = WSAGetLastError(); // Cleanup the network library without closing the handle WSACleanup(); return 0; } struct sockaddr_in si; si.sin_family = AF_INET; si.sin_port = htons(12345); // Use the htons macro to convert an integer into an unsigned integer for the port number si.sin_addr.s_un.s_addr = inet_addr("127.0.0.1");Copy the code

5. Bind the IP address and port

if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr*)&si, sizeof(si))) { int err = WSAGetLastError(); Printf (" server bind failed with error code: %d\n", err); closesocket(socketServer); / / WSACleanup release (); Return 0; } printf(" Server bind succeeded! \n");Copy the code

6. Start listening

if (SOCKET_ERROR == listen(socketServer, SOMAXCONN)) { int err = WSAGetLastError(); Printf (" server listening failed error code: %d\n", err); closesocket(socketServer); / / WSACleanup release (); Return 0; } printf(" Server listening successfully! \n");Copy the code

7,Event selection model

7.1 Defining the fD_sockEVENT_set structure

WSAEVENT eventServer = WSACreateEvent();
    if (eventServer == WSA_INVALID_EVENT)
    {
         int createerr = WSAGetLastError();

         closesocket(socketServer);

         WSACleanup();
         return 0;
}
Copy the code

7.2 Creating event Handles for the Server

if (WSAEventSelect(socketServer, eventServer, FD_ACCEPT) == SOCKET_ERROR)

    {

         int selecterr = WSAGetLastError();

         WSACloseEvent(eventServer);
         
         closesocket(socketServer);

         WSACleanup();

         return 0;

    }
Copy the code

7.3 Bind event code FD_ACCEPT to the SOCEKT and event handle of the server and add the event code

sockevent_set

sockevent_set.evnetall[sockevent_set.count] = eventServer;

sockevent_set.sockall[sockevent_set.count] = socketServer;

sockevent_set.count++;
Copy the code

7.4 Check the event status periodically. If no signal is displayed, query the event status again

7.4.1 Using WSAWaitForMultipleEvents to query the socket handle subscript corresponding to signaled events
DWORD soindex = retSignal - WSA_WAIT_EVENT_0;
Copy the code
7.4.2 Using WSAEnumNetworkEvents to Obtain the Event Operation Code
7.4.3 If the operation code is FD_ACCEPT
If (NetworkEvents lNetworkEvents & FD_ACCEPT) {/ / judgment FD_ACCEPT error code if there is a value corresponding to a the if (NetworkEvents. IErrorCode [FD_ACCEPT_BIT] = = SocketClient = accept(sockEVENT_set.sockAll [soindex], NULL, NULL); If (socketClient == INVALID_SOCKET) {continue; } WSAEVENT wsaClientEvent = WSACreateEvent(); If (wsaClientEvent == WSA_INVALID_EVENT) {closesocket(socketClient); continue; } // bind, If (WSAEventSelect(socketClient, wsaClientEvent, FD_READ | FD_WRITE | FD_CLOSE) = = SOCKET_ERROR) {/ / error close the handle to close the event object closesocket (socketClient); WSACloseEvent(wsaClientEvent); // Get the error code continue; Sockevent_set. evnetAll [sockEvent_set. count] = wsaClientEvent; sockevent_set.sockall[sockevent_set.count] = socketClient; sockevent_set.count++; } else {// An exception does not affect other processing continue; }}Copy the code
7.4.4 If the operation code is FD_WRITE
If (NetworkEvents lNetworkEvents & FD_WRITE) {/ / judgment error code if there is a value corresponding to a, If (NetworkEvents. IErrorCode [FD_WRITE_BIT] == 0) {if (send(sockEvent_set.sockall [soindex], "Connection successful ~", Sizeof (" connection succeeded ~"), 0) == SOCKET_ERROR) {int FD_WRITEsenderr = WSAGetLastError(); Printf (" error: %d\n", FD_WRITEsenderr); continue; }} else {printf(" get error code for FD_WRITE: %d\n", NetworkEvents. IErrorCode [FD_WRITE_BIT]); continue; }} # # # # # 7.4.5 if FD_READ opcode if (NetworkEvents. LNetworkEvents & FD_READ) {/ / judgment error code if there is a value corresponding to a, If (NetworkEvents. IErrorCode [FD_READ_BIT] == 0) {char strRecv[1500] = {0}; if (recv(sockevent_set.sockall[soindex], strRecv, sizeof(strRecv), 0) == SOCKET_ERROR) { int FD_READrecverr = WSAGetLastError(); Printf (" get error code: %d\n", FD_READrecverr); continue; } // Print the received message printf(" Received message: %s\n", strRecv); } else {printf(" get error code for FD_READ: %d\n", NetworkEvents. IErrorCode [FD_READ_BIT]); continue; }}Copy the code

7.4.5 If the operation code is FD_CLOSE

If (NetworkEvents lNetworkEvents & FD_CLOSE) {printf (" FD_CLOSE operation \ n "); Printf (" get error code for FD_CLOSE: %d\n", NetworkEvents. IErrorCode [FD_CLOSE_BIT]); Closesocket (sockEVENT_set.sockall [soindex]); // Clear the offline client socket closesocket(sockevent_set.sockall[soindex]); sockevent_set.sockall[soindex] = sockevent_set.sockall[sockevent_set.count - 1]; WSACloseEvent(sockEvent_set.evnetAll [soindex]); sockevent_set.evnetall[soindex] = sockevent_set.evnetall[sockevent_set.count - 1]; sockevent_set.count--; } for (int I = 0; i < sockevent_set.count; i++) { WSACloseEvent(sockevent_set.evnetall[i]); closesocket(sockevent_set.sockall[i]); } WSACleanup(); system("pause");Copy the code

The client

See the Select (TCP) model in the previous article

The results

How is the event selection model different from the SELECT model?

The Select model is the most common I/O model in Winsock. It is called the Select model because its “central idea” is to use the Select function to manage I/O. The model was originally designed for computers using the UNIX operating system using the Berkeley socket scheme. The Select model, which is integrated into Winsock 1.1, enables applications that want to avoid being “locked” innocently during socket calls to manage multiple sockets simultaneously in an orderly fashion. Because Winsock 1.1 is backward compatible with Berkeley socket implementations, if a Berkeley socket application uses the SELECT function, it should theoretically work without any modifications.

The event selection model is another useful asynchronous I/O model provided by Winsock. Like the WSAAsyncSelect model, it also allows an application to receive event-based notifications of network events on one or more sockets. Network events adopted by the WSAAsyncSelect model can be ported to the new model intact. All of those events can be received and processed in applications developed with the new model. The main difference is that network events are delivered to an event object handle rather than to a window routine.