windows TCP/IP 网络编程(三)5种windows网络模型(2) WsaEventSelect事件选择模型

在这里插入图片描述

1 windows处理用户行为的两种方式

在这里插入图片描述

2 事件选择的原理

在这里插入图片描述
在这里插入图片描述

3 事件选择步骤

3.1 处理事件的几个函数

3.1.1 创建一个事件对象 WSACreateEvent()

使用WSACreateEvent 函数创建一个新的事件对象。

语法

WSAEVENT WSAAPI WSACreateEvent();

返回值
如果未发生错误,WSACreateEvent 将返回事件对象的句柄。否则,返回值将WSA_INVALID_EVENT。要获取扩展的错误信息,请使用 WSAGetLastError。

在这里插入图片描述
内核对象

WSAEVENT event_server =  WSACreateEvent();
	if (WSA_INVALID_EVENT == event_server)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

3.1.2 释放事件 WSACloseEvent()

WSACloseEvent 函数关闭事件对象的句柄,并释放与该事件对象关联的资源。此函数用于关闭由 WSACreateEvent 函数创建的句柄。关闭事件对象的句柄后,对此句柄的进一步引用将失败,错误WSA_INVALID_HANDLE。
语法

BOOL WSAAPI WSACloseEvent(
  [in] WSAEVENT hEvent
);

参数

[in] hEvent

标识打开事件的对象句柄。

返回值

  • 如果函数成功,则返回值为 TRUE。
  • 如果函数失败,则返回值为 FALSE。要获取扩展的错误信息,请使用WSAGetLastError。

3.1.3 WSASetEvent 函数

WSASetEvent 函数将指定事件对象的状态设置为"已发出信号"
语法

BOOL WSAAPI WSASetEvent(
  [in] WSAEVENT hEvent
);

参数
[in] hEvent

标识打开的事件对象的句柄。

返回值

  • 如果函数成功,则返回值为 TRUE。
  • 如果函数失败,则返回值为 FALSE。要获取扩展的错误信息,请使用 WSAGetLastError。

3.1.4 WSAResetEvent 函数

WSAResetEvent 函数将指定事件对象的状态重置为非信号。
语法

BOOL WSAAPI WSAResetEvent(
  [in] WSAEVENT hEvent
);

参数
[in] hEvent
标识打开的事件对象句柄的句柄。
返回值

  • 如果 WSAResetEvent 函数成功,则返回值为 TRUE。
  • 如果函数失败,则返回值为 FALSE。要获取扩展的错误信息,请使用 WSAGetLastError。

3.2 绑定并投递

给事件绑上socket与操作码,并投递给操作系统
在这里插入图片描述

WSAEventSelect 函数指定要与指定的一组FD_XXX网络事件相关联的事件对象。
语法

int WSAAPI WSAEventSelect(
  [in] SOCKET   s,
  [in] WSAEVENT hEventObject,
  [in] long     lNetworkEvents
);

参数

[in] s
标识套接字的描述符。
[in] hEventObject
标识要与指定的FD_XXX网络事件集关联的事件对象的句柄。
[in] lNetworkEvents
一个位掩码,它指定应用程序感兴趣的FD_XXX网络事件的组合。

返回值

  • 如果应用程序对网络事件和关联事件对象的规范成功,则返回值为零。
  • 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误号。

3.3 询问事件 WSAWaitForMultipleEvents

当一个或所有指定的事件对象处于信号状态、超时间隔过期或执行 I/O 完成例程时,WSAWaitForMultipleEvents 函数将返回。
语法

DWORD WSAAPI WSAWaitForMultipleEvents(
  [in] DWORD          cEvents,
  [in] const WSAEVENT *lphEvents,
  [in] BOOL           fWaitAll,
  [in] DWORD          dwTimeout,
  [in] BOOL           fAlertable
);

参数
[in] cEvents
lphEvents 所指向的数组中的事件对象句柄数。最大事件对象句柄数为 WSA_MAXIMUM_WAIT_EVENTS。必须指定一个或多个事件。

[in] lphEvents
指向事件对象句柄数组的指针。数组可以包含不同类型的对象的句柄。如果 fWaitAll 参数设置为 TRUE,则它可能不包含同一句柄的多个副本。如果其中一个句柄在等待仍处于挂起状态时关闭,则 WSAWaitForMultipleEvents 的行为是未定义的。

句柄必须具有"同步"访问权限。有关详细信息,请参阅标准访问权限。

[in] fWaitAll
指定等待类型的值。

  • 如果为 TRUE,则在向 lphEvents 数组中所有对象的状态发出信号时返回该函数。阻塞
  • 如果为 FALSE,则在向任何事件对象发出信号时返回该函数。在后一种情况下,返回值减去 WSA_WAIT_EVENT_0 表示其状态导致函数返回的事件对象的索引。如果在调用期间发出了多个事件对象的信号,则这是指向已发出信号事件对象的数组索引,其索引值是所有已信令事件对象中最小的。

[in] dwTimeout
超时间隔,以毫秒为单位。如果超时间隔过期,WSAWaitForMultipleEvents 将返回,即使不满足 fWaitAll 参数指定的条件也是如此。如果 dwTimeout 参数为零,则 WSAWaitForMultipleEvents 将测试指定事件对象的状态并立即返回。如果 dwTimeout WSA_INFINITE,WSAWaitForMultipleEvents 将永远等待;也就是说,超时间隔永不过期。

[in] fAlertable
一个值,该值指定是否将线程置于可警报的等待状态,以便系统可以执行 I/O 完成例程。如果为 TRUE,则线程将置于可警报的等待状态,并且当系统执行 I/O 完成例程时,WSAWaitForMultipleEvents 可以返回。在这种情况下,将返回WSA_WAIT_IO_COMPLETION,并且尚未发出正在等待的事件的信号。应用程序必须再次调用 WSAWaitForMultipleEvents 函数。如果为 FALSE,则线程不会处于可警报的等待状态,并且不会执行 I/O 完成例程。

返回值
如果 WSAWaitForMultipleEvents 函数成功,则成功时的返回值是以下值之一。

返回值意义
WSA_WAIT_EVENT_0到 (WSA_WAIT_EVENT_0 + c事件 - 1)如果 fWaitAll 参数为 TRUE,则返回值指示所有指定的事件对象都已发出信号。
如果 fWaitAll 参数为 FALSE,则返回值减去 WSA_WAIT_EVENT_0 指示满足等待的已发出信号的事件对象的 lphEvents 数组索引。如果在调用期间有多个事件对象发出信号,则返回值指示已发出信号事件对象的 lphEvents 数组索引,其索引值是所有已发出信号事件对象的最小索引值。
WSA_WAIT_IO_COMPLETION等待已由一个或多个已执行的 I/O 完成例程结束。正在等待的事件尚未发出信号。应用程序必须再次调用 WSAWaitForMultipleEvents 函数。仅当 fAlertable 参数为 TRUE 时,才能返回此返回值。
WSA_WAIT_TIMEOUT未满足已过的超时间隔和 fWaitAll 参数指定的条件。未执行任何 I/O 完成例程。

如果 WSAWaitForMultipleEvents 函数失败,则返回值为 WSA_WAIT_FAILED。

event_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.绑定并投递
	int res_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_event_select)
	{
		printf("event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("event_server close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("event_server close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		DWORD res_wait = WSAWaitForMultipleEvents(fd_es_set.count,
												  fd_es_set.all_event,
												  FALSE,
												  120/*等待120ms, WSA_INFINITE 无限等待*/,
												  FALSE);
		if (WSA_WAIT_FAILED == res_wait)//出错了
		{
			printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
			break;
		}
		//超时
		if (WSA_WAIT_TIMEOUT == res_wait)
		{
			printf("time out : %d\n", res_wait);
			continue;
		}
		DWORD index = res_wait - WSA_WAIT_EVENT_0;
	}

	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.4 列举事件

在这里插入图片描述
event_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.绑定并投递
	int res_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_event_select)
	{
		printf("event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("event_server close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("event_server close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		DWORD res_wait = WSAWaitForMultipleEvents(fd_es_set.count,
												  fd_es_set.all_event,
												  FALSE,
												  120/*等待120ms, WSA_INFINITE 无限等待*/,
												  FALSE);
		if (WSA_WAIT_FAILED == res_wait)//出错了
		{
			printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
			break;
		}
		//超时
		if (WSA_WAIT_TIMEOUT == res_wait)
		{
			printf("time out : %d\n", res_wait);
			continue;
		}
		DWORD index = res_wait - WSA_WAIT_EVENT_0;
		//等到下标对应的具体操作
		WSANETWORKEVENTS network_events;
		int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[index],
												   fd_es_set.all_event[index],
												   &network_events);
		if (SOCKET_ERROR == res_enum_events)
		{
			printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
			break;
		}
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.5 事件的分类处理

在这里插入图片描述
test_demo
event_select_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		DWORD res_wait_event = WSAWaitForMultipleEvents(fd_es_set.count,
												  fd_es_set.all_event,
												  FALSE,
												  WSA_INFINITE /*无限等待, 120等待120ms,*/,
												  FALSE);
		if (WSA_WAIT_FAILED == res_wait_event)//出错了
		{
			printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
			break;
		}
		//超时
		//if (WSA_WAIT_TIMEOUT == res_wait)
		//{
		//	printf("time out : %d\n", res_wait);
		//	continue;
		//}
		DWORD index = res_wait_event - WSA_WAIT_EVENT_0;

		//等到下标对应的具体操作
		WSANETWORKEVENTS network_events;
		int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[index],
												   fd_es_set.all_event[index],
												   &network_events);
		if (SOCKET_ERROR == res_enum_events)
		{
			printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
			break;
		}

		/*事件分类处理*/
		//处理FD_ACCEPT
		if (network_events.lNetworkEvents & FD_ACCEPT)
		{
			if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
			{
				//正常处理
				SOCKET socket_client = accept(fd_es_set.all_sock[index], NULL, NULL);
				if (INVALID_SOCKET == socket_client)
				{
					continue;
				}
				//为客户端创建事件对象
				WSAEVENT wsa_client_event = WSACreateEvent();
				if (WSA_INVALID_EVENT == wsa_client_event)
				{
					closesocket(socket_client);
					continue;
				}
				//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
				int res_client_event_select = WSAEventSelect(socket_client,
															 wsa_client_event,
															 FD_READ | FD_CLOSE | FD_WRITE);
				if (SOCKET_ERROR == res_client_event_select)
				{
					printf("client_event_select error,error_code:%d\n", WSAGetLastError());
					//关闭、释放事件
					BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
					if (TRUE == colse_event_flag)
					{
						printf("wsa_client_event close success\n");
					}
					else if (FALSE == colse_event_flag)
					{
						printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
					}
					//关闭socket
					closesocket(socket_client);
					//关闭网络库
					WSACleanup();//关闭网络库
					return -1;
				}
				//装进结构体
				fd_es_set.all_sock[fd_es_set.count] = socket_client;
				fd_es_set.all_event[fd_es_set.count] = wsa_client_event;
				fd_es_set.count++;

				printf("accept event\n");
			}
			else
			{
				printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_ACCEPT_BIT]);
				continue;
			}
		}

		//处理FD_WRITE
		if (network_events.lNetworkEvents & FD_WRITE)
		{
			if (0 == network_events.iErrorCode[FD_WRITE_BIT])
			{
				//初始化
				//int res_send = send(fd_es_set.all_sock[index], "connect success",
				//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
				int res_send = send(fd_es_set.all_sock[index], "connect success",
									strlen("connect success"), 0);//strlen()不包括'\0'
				if (SOCKET_ERROR == res_send)
				{
					printf("send error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				printf("write event\n");
			}
			else
			{
				printf("network_events FD_WRITE | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_WRITE_BIT]);
				continue;
			}
		}

		//处理FD_READ
		if (network_events.lNetworkEvents & FD_READ)
		{
			if (0 == network_events.iErrorCode[FD_READ_BIT])
			{
				char recv_buf[1500] = { 0 };
				int res_recv = recv(fd_es_set.all_sock[index], recv_buf, 1499, 0);
				if (SOCKET_ERROR == res_recv)
				{
					printf("recv error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				printf("recv data:%s\n", recv_buf);
			}
			else
			{
				printf("network_events FD_READ | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_READ_BIT]);
			}
		}

		//处理FD_CLOSE
		if (network_events.lNetworkEvents & FD_CLOSE)
		{
			//if (0 == network_events.iErrorCode[FD_CLOSE_BIT])
			//{
			//
			//}
			//else
			//{
			//}
			//WSAECONNABORTED;
			printf("client close\n");
			printf("network_events FD_CLOSE | socket error, error_code:%d\n",
				   network_events.iErrorCode[FD_CLOSE_BIT]);
			//清理下线客户端 的 套接字 和 事件
			//清理套接字
			closesocket(fd_es_set.all_sock[index]);
			fd_es_set.all_sock[index] = fd_es_set.all_sock[fd_es_set.count - 1];
			//清理事件
			WSACloseEvent(fd_es_set.all_event[index]);
			fd_es_set.all_event[index] = fd_es_set.all_event[fd_es_set.count - 1];
			//数量减1
			fd_es_set.count--;
		}
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

client.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")

int main(void)
{
	WORD wdVersion = MAKEWORD(2, 2); 
	WSADATA wdScokMsg;
	int nRes = WSAStartup(wdVersion, &wdScokMsg);

	if (0 != nRes)
	{
		switch (nRes)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库");
			break;
		case WSAEINPROGRESS:
			printf("请重新启动");
			break;
		case WSAEPROCLIM:
			printf("请尝试关掉不必要的软件,以为当前网络运行提供充足资源");
			break;
		}

		return 0;
	}

	//校验版本
	if (2 != HIBYTE(wdScokMsg.wVersion) || 2 != LOBYTE(wdScokMsg.wVersion))
	{
		//说明版本不对
		//清理网络库
		WSACleanup();
		return 0;
	}

	//服务器socket
	SOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socketServer)
	{
		int a = WSAGetLastError();
		//清理网络库
		WSACleanup();
		return 0;
	}

	//链接服务器
	struct sockaddr_in serverMsg;
	serverMsg.sin_family = AF_INET;
	serverMsg.sin_port = htons(12345);
	serverMsg.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	if (SOCKET_ERROR == connect(socketServer, (struct sockaddr*)&serverMsg, sizeof(serverMsg)))
	{
		int a = WSAGetLastError();
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	while (1)
	{
		char buf[1500] = { 0 };
		scanf("%s", buf);
		if ('q' == buf[0])//当输入q的时候退出循环,关闭程序,正常下线
		{
			break;
		}
		if (SOCKET_ERROR == send(socketServer, buf, strlen(buf), 0))
		{
			//出错了
			int a = WSAGetLastError();
			//根据实际情况处理
			printf("%d\n", a);
		}
	}

	//清理网络库
	closesocket(socketServer);
	WSACleanup();

	system("pause");
	return 0;
}

3.6 有序化之变态点击

在这里插入图片描述

3.6.1 优化1

在这里插入图片描述
5个客户端轮询,

	while(1)
	{
		1;
		2;
		3;
		4;
		5;
	}

event_select_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		for (int index = 0; index < fd_es_set.count; index++)
		{
			//一次只询问一个
			DWORD res_wait_event = WSAWaitForMultipleEvents(1,
															&fd_es_set.all_event[index],
															FALSE,
															0,/*不等待,有没有信号都立即返回*/
															FALSE);
			if (WSA_WAIT_FAILED == res_wait_event)//出错了
			{
				printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
				continue;
			}
			//超时
			if (WSA_WAIT_TIMEOUT == res_wait_event)
			{
				//printf("WSAWaitForMultipleEvents timeout\n");
				continue;
			}

			//等到下标对应的具体操作
			WSANETWORKEVENTS network_events;
			int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[index],
													   fd_es_set.all_event[index],
													   &network_events);
			if (SOCKET_ERROR == res_enum_events)
			{
				printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
				break;
			}

			/*事件分类处理*/
			//处理FD_ACCEPT
			if (network_events.lNetworkEvents & FD_ACCEPT)
			{
				if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
				{
					//正常处理
					SOCKET socket_client = accept(fd_es_set.all_sock[index], NULL, NULL);
					if (INVALID_SOCKET == socket_client)
					{
						continue;
					}
					//为客户端创建事件对象
					WSAEVENT wsa_client_event = WSACreateEvent();
					if (WSA_INVALID_EVENT == wsa_client_event)
					{
						closesocket(socket_client);
						continue;
					}
					//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
					int res_client_event_select = WSAEventSelect(socket_client,
																 wsa_client_event,
																 FD_READ | FD_CLOSE | FD_WRITE);
					if (SOCKET_ERROR == res_client_event_select)
					{
						printf("client_event_select error,error_code:%d\n", WSAGetLastError());
						//关闭、释放事件
						BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
						if (TRUE == colse_event_flag)
						{
							printf("wsa_client_event close success\n");
						}
						else if (FALSE == colse_event_flag)
						{
							printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
						}
						//关闭socket
						closesocket(socket_client);
						//关闭网络库
						WSACleanup();//关闭网络库
						return -1;
					}
					//装进结构体
					fd_es_set.all_sock[fd_es_set.count] = socket_client;
					fd_es_set.all_event[fd_es_set.count] = wsa_client_event;
					fd_es_set.count++;

					printf("accept event\n");
				}
				else
				{
					printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_ACCEPT_BIT]);
					continue;
				}
			}

			//处理FD_WRITE
			if (network_events.lNetworkEvents & FD_WRITE)
			{
				if (0 == network_events.iErrorCode[FD_WRITE_BIT])
				{
					//初始化
					//int res_send = send(fd_es_set.all_sock[index], "connect success",
					//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
					int res_send = send(fd_es_set.all_sock[index], "connect success",
										strlen("connect success"), 0);//strlen()不包括'\0'
					if (SOCKET_ERROR == res_send)
					{
						printf("send error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("write event\n");
				}
				else
				{
					printf("network_events FD_WRITE | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_WRITE_BIT]);
					continue;
				}
			}

			//处理FD_READ
			if (network_events.lNetworkEvents & FD_READ)
			{
				if (0 == network_events.iErrorCode[FD_READ_BIT])
				{
					char recv_buf[1500] = { 0 };
					int res_recv = recv(fd_es_set.all_sock[index], recv_buf, 1499, 0);
					if (SOCKET_ERROR == res_recv)
					{
						printf("recv error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("recv data:%s\n", recv_buf);
				}
				else
				{
					printf("network_events FD_READ | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_READ_BIT]);
				}
			}

			//处理FD_CLOSE
			if (network_events.lNetworkEvents & FD_CLOSE)
			{
				printf("client close\n");
				printf("network_events FD_CLOSE | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_CLOSE_BIT]);
				//清理下线客户端 的 套接字 和 事件
				//清理套接字
				closesocket(fd_es_set.all_sock[index]);
				fd_es_set.all_sock[index] = fd_es_set.all_sock[fd_es_set.count - 1];
				//清理事件
				WSACloseEvent(fd_es_set.all_event[index]);
				fd_es_set.all_event[index] = fd_es_set.all_event[fd_es_set.count - 1];
				//数量减1
				fd_es_set.count--;
			}

		}		
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.6.2 优化2

在这里插入图片描述
在这里插入图片描述

先得到有事件的下标,再从该客户端下标处轮询
event_select_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		DWORD res_wait = WSAWaitForMultipleEvents(fd_es_set.count,
												  fd_es_set.all_event,
												  FALSE,
												  120/*等待120ms, WSA_INFINITE 无限等待*/,
												  FALSE);
		if (WSA_WAIT_FAILED == res_wait)//出错了
		{
			printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
			continue;
		}
		DWORD index = res_wait - WSA_WAIT_EVENT_0;//先得到第一个触发事件的客户端的下标

		for (int i = index; i < fd_es_set.count; i++)
		{
			//一次只询问一个
			DWORD res_wait_event = WSAWaitForMultipleEvents(1,
															&fd_es_set.all_event[i],
															FALSE,
															0,/*不等待,有没有信号都立即返回*/
															FALSE);
			if (WSA_WAIT_FAILED == res_wait_event)//出错了
			{
				printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
				continue;
			}
			//超时
			if (WSA_WAIT_TIMEOUT == res_wait_event)
			{
				//printf("WSAWaitForMultipleEvents timeout\n");
				continue;
			}

			//等到下标对应的具体操作
			WSANETWORKEVENTS network_events;
			int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[i],
													   fd_es_set.all_event[i],
													   &network_events);
			if (SOCKET_ERROR == res_enum_events)
			{
				printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
				break;
			}

			/*事件分类处理*/
			//处理FD_ACCEPT
			if (network_events.lNetworkEvents & FD_ACCEPT)
			{
				if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
				{
					//正常处理
					SOCKET socket_client = accept(fd_es_set.all_sock[i], NULL, NULL);
					if (INVALID_SOCKET == socket_client)
					{
						continue;
					}
					//为客户端创建事件对象
					WSAEVENT wsa_client_event = WSACreateEvent();
					if (WSA_INVALID_EVENT == wsa_client_event)
					{
						closesocket(socket_client);
						continue;
					}
					//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
					int res_client_event_select = WSAEventSelect(socket_client,
																 wsa_client_event,
																 FD_READ | FD_CLOSE | FD_WRITE);
					if (SOCKET_ERROR == res_client_event_select)
					{
						printf("client_event_select error,error_code:%d\n", WSAGetLastError());
						//关闭、释放事件
						BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
						if (TRUE == colse_event_flag)
						{
							printf("wsa_client_event close success\n");
						}
						else if (FALSE == colse_event_flag)
						{
							printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
						}
						//关闭socket
						closesocket(socket_client);
						//关闭网络库
						WSACleanup();//关闭网络库
						return -1;
					}
					//装进结构体
					fd_es_set.all_sock[fd_es_set.count] = socket_client;
					fd_es_set.all_event[fd_es_set.count] = wsa_client_event;
					fd_es_set.count++;

					printf("accept event\n");
				}
				else
				{
					printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_ACCEPT_BIT]);
					continue;
				}
			}

			//处理FD_WRITE
			if (network_events.lNetworkEvents & FD_WRITE)
			{
				if (0 == network_events.iErrorCode[FD_WRITE_BIT])
				{
					//初始化
					//int res_send = send(fd_es_set.all_sock[index], "connect success",
					//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
					int res_send = send(fd_es_set.all_sock[i], "connect success",
										strlen("connect success"), 0);//strlen()不包括'\0'
					if (SOCKET_ERROR == res_send)
					{
						printf("send error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("write event\n");
				}
				else
				{
					printf("network_events FD_WRITE | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_WRITE_BIT]);
					continue;
				}
			}

			//处理FD_READ
			if (network_events.lNetworkEvents & FD_READ)
			{
				if (0 == network_events.iErrorCode[FD_READ_BIT])
				{
					char recv_buf[1500] = { 0 };
					int res_recv = recv(fd_es_set.all_sock[i], recv_buf, 1499, 0);
					if (SOCKET_ERROR == res_recv)
					{
						printf("recv error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("recv data:%s\n", recv_buf);
				}
				else
				{
					printf("network_events FD_READ | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_READ_BIT]);
				}
			}

			//处理FD_CLOSE
			if (network_events.lNetworkEvents & FD_CLOSE)
			{
				printf("client close\n");
				printf("network_events FD_CLOSE | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_CLOSE_BIT]);
				//清理下线客户端 的 套接字 和 事件
				//清理套接字
				closesocket(fd_es_set.all_sock[i]);
				fd_es_set.all_sock[i] = fd_es_set.all_sock[fd_es_set.count - 1];
				//清理事件
				WSACloseEvent(fd_es_set.all_event[i]);
				fd_es_set.all_event[i] = fd_es_set.all_event[fd_es_set.count - 1];
				//数量减1
				fd_es_set.count--;
			}

		}		
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.7 增加事件数量

在这里插入图片描述
(WSAWaitForMultipleEvents()函数调用一次)1组最大64个事件
在这里插入图片描述

3.7.1 一个一个的投递

数组容量扩大

在这里插入图片描述

event_select_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[1024];
	WSAEVENT all_event[1024];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		for (int i = 0; i < fd_es_set.count; i++)
		{
			//一次只询问一个
			DWORD res_wait_event = WSAWaitForMultipleEvents(1,
															&fd_es_set.all_event[i],
															FALSE,
															0,/*不等待,有没有信号都立即返回*/
															FALSE);
			if (WSA_WAIT_FAILED == res_wait_event)//出错了
			{
				printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
				continue;
			}
			//超时
			if (WSA_WAIT_TIMEOUT == res_wait_event)
			{
				//printf("WSAWaitForMultipleEvents timeout\n");
				continue;
			}

			//等到下标对应的具体操作
			WSANETWORKEVENTS network_events;
			int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[i],
													   fd_es_set.all_event[i],
													   &network_events);
			if (SOCKET_ERROR == res_enum_events)
			{
				printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
				break;
			}

			/*事件分类处理*/
			//处理FD_ACCEPT
			if (network_events.lNetworkEvents & FD_ACCEPT)
			{
				if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
				{
					//正常处理
					SOCKET socket_client = accept(fd_es_set.all_sock[i], NULL, NULL);
					if (INVALID_SOCKET == socket_client)
					{
						continue;
					}
					//为客户端创建事件对象
					WSAEVENT wsa_client_event = WSACreateEvent();
					if (WSA_INVALID_EVENT == wsa_client_event)
					{
						closesocket(socket_client);
						continue;
					}
					//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
					int res_client_event_select = WSAEventSelect(socket_client,
																 wsa_client_event,
																 FD_READ | FD_CLOSE | FD_WRITE);
					if (SOCKET_ERROR == res_client_event_select)
					{
						printf("client_event_select error,error_code:%d\n", WSAGetLastError());
						//关闭、释放事件
						BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
						if (TRUE == colse_event_flag)
						{
							printf("wsa_client_event close success\n");
						}
						else if (FALSE == colse_event_flag)
						{
							printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
						}
						//关闭socket
						closesocket(socket_client);
						//关闭网络库
						WSACleanup();//关闭网络库
						return -1;
					}
					//装进结构体
					fd_es_set.all_sock[fd_es_set.count] = socket_client;
					fd_es_set.all_event[fd_es_set.count] = wsa_client_event;
					fd_es_set.count++;

					printf("accept event\n");
				}
				else
				{
					printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_ACCEPT_BIT]);
					continue;
				}
			}

			//处理FD_WRITE
			if (network_events.lNetworkEvents & FD_WRITE)
			{
				if (0 == network_events.iErrorCode[FD_WRITE_BIT])
				{
					//初始化
					//int res_send = send(fd_es_set.all_sock[index], "connect success",
					//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
					int res_send = send(fd_es_set.all_sock[i], "connect success",
										strlen("connect success"), 0);//strlen()不包括'\0'
					if (SOCKET_ERROR == res_send)
					{
						printf("send error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("write event\n");
				}
				else
				{
					printf("network_events FD_WRITE | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_WRITE_BIT]);
					continue;
				}
			}

			//处理FD_READ
			if (network_events.lNetworkEvents & FD_READ)
			{
				if (0 == network_events.iErrorCode[FD_READ_BIT])
				{
					char recv_buf[1500] = { 0 };
					int res_recv = recv(fd_es_set.all_sock[i], recv_buf, 1499, 0);
					if (SOCKET_ERROR == res_recv)
					{
						printf("recv error, error_code:%d\n", WSAGetLastError());
						continue;
					}
					printf("recv data:%s\n", recv_buf);
				}
				else
				{
					printf("network_events FD_READ | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_READ_BIT]);
				}
			}

			//处理FD_CLOSE
			if (network_events.lNetworkEvents & FD_CLOSE)
			{
				printf("client close\n");
				printf("network_events FD_CLOSE | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_CLOSE_BIT]);
				//清理下线客户端 的 套接字 和 事件
				//清理套接字
				closesocket(fd_es_set.all_sock[i]);
				fd_es_set.all_sock[i] = fd_es_set.all_sock[fd_es_set.count - 1];
				//清理事件
				WSACloseEvent(fd_es_set.all_event[i]);
				fd_es_set.all_event[i] = fd_es_set.all_event[fd_es_set.count - 1];
				//数量减1
				fd_es_set.count--;
			}

		}		
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.7.2 一组一组的投递

在这里插入图片描述在这里插入图片描述
event_select_server.c

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	struct fd_event_socket_set fd_es_set[20];//20组
	memset(fd_es_set, 0, sizeof(struct fd_event_socket_set)* 20);//赋值

	//1.创建事件
	WSAEVENT server_event =  WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set[0].all_event[fd_es_set[0].count] = server_event;
	fd_es_set[0].all_sock[fd_es_set[0].count] = socket_server;
	fd_es_set[0].count++;
	while (1)
	{
		for (int j = 0; j < 20; j++)
		{		
			if (0 == fd_es_set[j].count)
			{
				continue;
			}
			//先在一组里面找到有事件的那个
			DWORD res_wait = WSAWaitForMultipleEvents(fd_es_set[j].count,
													  fd_es_set[j].all_event,
													  FALSE,
													  0,
													  FALSE);
			if (WSA_WAIT_FAILED == res_wait)//出错了
			{
				printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
				continue;
			}
			if (WSA_WAIT_TIMEOUT == res_wait)
			{
				continue;
			}
			DWORD index = res_wait - WSA_WAIT_EVENT_0;//先得到第一个触发事件的客户端的下标

			for (int i = index; i < fd_es_set[j].count; i++)
			{
				//一次只询问一个
				DWORD res_wait_event = WSAWaitForMultipleEvents(1,
																&fd_es_set[j].all_event[i],
																FALSE,
																0,/*不等待,有没有信号都立即返回*/
																FALSE);
				if (WSA_WAIT_FAILED == res_wait_event)//出错了
				{
					printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				//超时
				if (WSA_WAIT_TIMEOUT == res_wait_event)
				{
					//printf("WSAWaitForMultipleEvents timeout\n");
					continue;
				}

				//等到下标对应的具体操作
				WSANETWORKEVENTS network_events;
				int res_enum_events = WSAEnumNetworkEvents(fd_es_set[j].all_sock[i],
														   fd_es_set[j].all_event[i],
														   &network_events);
				if (SOCKET_ERROR == res_enum_events)
				{
					printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
					break;
				}

				/*事件分类处理*/
				//处理FD_ACCEPT
				if (network_events.lNetworkEvents & FD_ACCEPT)
				{
					if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
					{
						//正常处理
						SOCKET socket_client = accept(fd_es_set[j].all_sock[i], NULL, NULL);
						if (INVALID_SOCKET == socket_client)
						{
							continue;
						}
						//为客户端创建事件对象
						WSAEVENT wsa_client_event = WSACreateEvent();
						if (WSA_INVALID_EVENT == wsa_client_event)
						{
							closesocket(socket_client);
							continue;
						}
						//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
						int res_client_event_select = WSAEventSelect(socket_client,
																	 wsa_client_event,
																	 FD_READ | FD_CLOSE | FD_WRITE);
						if (SOCKET_ERROR == res_client_event_select)
						{
							printf("client_event_select error,error_code:%d\n", WSAGetLastError());
							//关闭、释放事件
							BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
							if (TRUE == colse_event_flag)
							{
								printf("wsa_client_event close success\n");
							}
							else if (FALSE == colse_event_flag)
							{
								printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
							}
							//关闭socket
							closesocket(socket_client);
							//关闭网络库
							WSACleanup();//关闭网络库
							return -1;
						}

						for (int k = 0; k < 20; k++)
						{
							if (fd_es_set[k].count < 64)
							{
								//装进结构体
								fd_es_set[k].all_sock[fd_es_set[k].count] = socket_client;
								fd_es_set[k].all_event[fd_es_set[k].count] = wsa_client_event;
								fd_es_set[k].count++;
								break;
							}
						}

						printf("accept event\n");
					}
					else
					{
						printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_ACCEPT_BIT]);
						continue;
					}
				}

				//处理FD_WRITE
				if (network_events.lNetworkEvents & FD_WRITE)
				{
					if (0 == network_events.iErrorCode[FD_WRITE_BIT])
					{
						//初始化
						//int res_send = send(fd_es_set.all_sock[index], "connect success",
						//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
						int res_send = send(fd_es_set[j].all_sock[i], "connect success",
											strlen("connect success"), 0);//strlen()不包括'\0'
						if (SOCKET_ERROR == res_send)
						{
							printf("send error, error_code:%d\n", WSAGetLastError());
							continue;
						}
						printf("write event\n");
					}
					else
					{
						printf("network_events FD_WRITE | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_WRITE_BIT]);
						continue;
					}
				}

				//处理FD_READ
				if (network_events.lNetworkEvents & FD_READ)
				{
					if (0 == network_events.iErrorCode[FD_READ_BIT])
					{
						char recv_buf[1500] = { 0 };
						int res_recv = recv(fd_es_set[j].all_sock[i], recv_buf, 1499, 0);
						if (SOCKET_ERROR == res_recv)
						{
							printf("recv error, error_code:%d\n", WSAGetLastError());
							continue;
						}
						printf("recv data:%s\n", recv_buf);
					}
					else
					{
						printf("network_events FD_READ | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_READ_BIT]);
					}
				}

				//处理FD_CLOSE
				if (network_events.lNetworkEvents & FD_CLOSE)
				{
					printf("client close\n");
					printf("network_events FD_CLOSE | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_CLOSE_BIT]);
					//清理下线客户端 的 套接字 和 事件
					//清理套接字
					closesocket(fd_es_set[j].all_sock[i]);
					fd_es_set[j].all_sock[i] = fd_es_set[j].all_sock[fd_es_set[j].count - 1];
					//清理事件
					WSACloseEvent(fd_es_set[j].all_event[i]);
					fd_es_set[j].all_event[i] = fd_es_set[j].all_event[fd_es_set[j].count - 1];
					//数量减1
					fd_es_set[j].count--;
				}

			}
		}
	}


	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.8 释放

3.8.1 优化前

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
struct fd_event_socket_set fd_es_set = { 0, { 0 }, { NULL } };

BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
			for (int i = 0; i < fd_es_set.count; i++)
			{
				closesocket(fd_es_set.all_sock[i]);
				WSACloseEvent(fd_es_set.all_event[i]);
			}
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/

	//1.创建事件
	WSAEVENT server_event = WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set.all_event[fd_es_set.count] = server_event;
	fd_es_set.all_sock[fd_es_set.count] = socket_server;
	fd_es_set.count++;
	while (1)
	{
		DWORD res_wait_event = WSAWaitForMultipleEvents(fd_es_set.count,
														fd_es_set.all_event,
														FALSE,
														WSA_INFINITE /*无限等待, 120等待120ms,*/,
														FALSE);
		if (WSA_WAIT_FAILED == res_wait_event)//出错了
		{
			printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
			break;
		}
		//超时
		//if (WSA_WAIT_TIMEOUT == res_wait)
		//{
		//	printf("time out : %d\n", res_wait);
		//	continue;
		//}
		DWORD index = res_wait_event - WSA_WAIT_EVENT_0;

		//等到下标对应的具体操作
		WSANETWORKEVENTS network_events;
		int res_enum_events = WSAEnumNetworkEvents(fd_es_set.all_sock[index],
												   fd_es_set.all_event[index],
												   &network_events);
		if (SOCKET_ERROR == res_enum_events)
		{
			printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
			break;
		}

		/*事件分类处理*/
		//处理FD_ACCEPT
		if (network_events.lNetworkEvents & FD_ACCEPT)
		{
			if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
			{
				//正常处理
				SOCKET socket_client = accept(fd_es_set.all_sock[index], NULL, NULL);
				if (INVALID_SOCKET == socket_client)
				{
					continue;
				}
				//为客户端创建事件对象
				WSAEVENT wsa_client_event = WSACreateEvent();
				if (WSA_INVALID_EVENT == wsa_client_event)
				{
					closesocket(socket_client);
					continue;
				}
				//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
				int res_client_event_select = WSAEventSelect(socket_client,
															 wsa_client_event,
															 FD_READ | FD_CLOSE | FD_WRITE);
				if (SOCKET_ERROR == res_client_event_select)
				{
					printf("client_event_select error,error_code:%d\n", WSAGetLastError());
					//关闭、释放事件
					BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
					if (TRUE == colse_event_flag)
					{
						printf("wsa_client_event close success\n");
					}
					else if (FALSE == colse_event_flag)
					{
						printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
					}
					//关闭socket
					closesocket(socket_client);
					//关闭网络库
					WSACleanup();//关闭网络库
					return -1;
				}
				//装进结构体
				fd_es_set.all_sock[fd_es_set.count] = socket_client;
				fd_es_set.all_event[fd_es_set.count] = wsa_client_event;
				fd_es_set.count++;

				printf("accept event\n");
			}
			else
			{
				printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_ACCEPT_BIT]);
				continue;
			}
		}

		//处理FD_WRITE
		if (network_events.lNetworkEvents & FD_WRITE)
		{
			if (0 == network_events.iErrorCode[FD_WRITE_BIT])
			{
				//初始化
				//int res_send = send(fd_es_set.all_sock[index], "connect success",
				//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
				int res_send = send(fd_es_set.all_sock[index], "connect success",
									strlen("connect success"), 0);//strlen()不包括'\0'
				if (SOCKET_ERROR == res_send)
				{
					printf("send error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				printf("write event\n");
			}
			else
			{
				printf("network_events FD_WRITE | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_WRITE_BIT]);
				continue;
			}
		}

		//处理FD_READ
		if (network_events.lNetworkEvents & FD_READ)
		{
			if (0 == network_events.iErrorCode[FD_READ_BIT])
			{
				char recv_buf[1500] = { 0 };
				int res_recv = recv(fd_es_set.all_sock[index], recv_buf, 1499, 0);
				if (SOCKET_ERROR == res_recv)
				{
					printf("recv error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				printf("recv data:%s\n", recv_buf);
			}
			else
			{
				printf("network_events FD_READ | socket error, error_code:%d\n",
					   network_events.iErrorCode[FD_READ_BIT]);
			}
		}

		//处理FD_CLOSE
		if (network_events.lNetworkEvents & FD_CLOSE)
		{
			//if (0 == network_events.iErrorCode[FD_CLOSE_BIT])
			//{
			//
			//}
			//else
			//{
			//}
			//WSAECONNABORTED;
			printf("client close\n");
			printf("network_events FD_CLOSE | socket error, error_code:%d\n",
				   network_events.iErrorCode[FD_CLOSE_BIT]);
			//清理下线客户端 的 套接字 和 事件
			//清理套接字
			closesocket(fd_es_set.all_sock[index]);
			fd_es_set.all_sock[index] = fd_es_set.all_sock[fd_es_set.count - 1];
			//清理事件
			WSACloseEvent(fd_es_set.all_event[index]);
			fd_es_set.all_event[index] = fd_es_set.all_event[fd_es_set.count - 1];
			//数量减1
			fd_es_set.count--;
		}
	}

	for (int i = 0; i < fd_es_set.count; i++)
	{
		closesocket(fd_es_set.all_sock[i]);
		WSACloseEvent(fd_es_set.all_event[i]);
	}

	//2.关闭、释放事件
	BOOL colse_event_flag = WSACloseEvent(server_event);
	if (TRUE == colse_event_flag)
	{
		printf("event_server close success\n");
	}
	else if (FALSE == colse_event_flag)
	{
		printf("event_server close failed,error_code:%d\n", WSAGetLastError());
	}

	/*程序结束先关闭socket,再关闭网络库;因为socket是网络库里面的函数*/
	closesocket(socket_server);

	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

3.8.2 一组一组

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32.lib")

//存储所有socket和event的结构体
typedef struct fd_event_socket_set
{
	unsigned short count;
	SOCKET all_sock[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT all_event[WSA_MAXIMUM_WAIT_EVENTS];
};

fd_set fd_set_socks;//装服务端和多个客户端的集合
struct fd_event_socket_set fd_es_set[20];//20组

BOOL WINAPI fun(DWORD dw_ctrl_type)
{
	switch (dw_ctrl_type)
	{
	case CTRL_CLOSE_EVENT:
	{
		{
			/*释放所有的socket*/
			for (int j = 0; j < 20;j++)
			{
				for (int i = 0; i < fd_es_set[j].count; i++)
				{
					closesocket(fd_es_set[j].all_sock[i]);
					WSACloseEvent(fd_es_set[j].all_event[i]);
				}
			}
		}
	}
		break;
	default:
		break;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	SetConsoleCtrlHandler(fun, TRUE);

	/*打开网络库*/
	WORD ws_verson = MAKEWORD(2, 2);
	WSADATA wd_sock_msg;
	int ret = WSAStartup(ws_verson, &wd_sock_msg);
	if (0 != ret)
	{
		switch (ret)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库!");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库!");
			break;
		case WSAEPROCLIM:
			printf("请重新启动!");
			break;
		case WSAEINPROGRESS:
			printf("请尝试关掉不必要的软件,为当前网络运行提供充足资源!");
			break;
		case WSAEFAULT:
			printf("参数错误!");
			break;
		default:
			break;
		}
		return 0;
	}
	printf("网络库打开成功!\n");

	/*检查版本*/
	if (2 != LOBYTE(wd_sock_msg.wVersion) || //地位-》得到主版本
		2 != HIBYTE(wd_sock_msg.wVersion))   //高位-》得到副版本
	{
		//说明版本不对,要关闭网络库
		WSACleanup();
		return -1;
	}
	printf("网络库版本号:(%d,%d)\n", LOBYTE(wd_sock_msg.wVersion), HIBYTE(wd_sock_msg.wVersion));

	/*创建套接字*/
	SOCKET socket_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == socket_server)
	{
		printf("socket_server created failed,error_code:%d\n", WSAGetLastError());
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("socket_server created success,return code:%d\n", socket_server);

	/*绑定地址*/
	struct  sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int res_bind = bind(socket_server, (const struct sockaddr *) &si, sizeof(si));
	if (SOCKET_ERROR == res_bind)
	{
		printf("bind failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("bind success,return code:%d\n", res_bind);

	/*监听listen*/
	int res_listen = listen(socket_server, SOMAXCONN);
	if (SOCKET_ERROR == res_listen)
	{
		printf("listen failed,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}
	else
		printf("listen success,return code:%d\n", res_listen);

	/*event select 事件*/
	

	//1.创建事件
	WSAEVENT server_event = WSACreateEvent();
	if (WSA_INVALID_EVENT == server_event)
	{
		printf("event_server error,error_code:%d\n", WSAGetLastError());
		closesocket(socket_server);
		WSACleanup();//关闭网络库
		return -1;
	}

	//2.将服务端绑定并投递
	int res_server_event_select = WSAEventSelect(socket_server, server_event, FD_ACCEPT);
	if (SOCKET_ERROR == res_server_event_select)
	{
		printf("server_event_select error,error_code:%d\n", WSAGetLastError());
		//关闭、释放事件
		BOOL colse_event_flag = WSACloseEvent(server_event);
		if (TRUE == colse_event_flag)
		{
			printf("server_event close success\n");
		}
		else if (FALSE == colse_event_flag)
		{
			printf("server_event close failed,error_code:%d\n", WSAGetLastError());
		}
		//关闭socket
		closesocket(socket_server);
		//关闭网络库
		WSACleanup();//关闭网络库
		return -1;
	}

	/*询问事件*/
	//将服务端事件装进去
	fd_es_set[0].all_event[fd_es_set[0].count] = server_event;
	fd_es_set[0].all_sock[fd_es_set[0].count] = socket_server;
	fd_es_set[0].count++;
	while (1)
	{
		for (int j = 0; j < 20; j++)
		{
			if (0 == fd_es_set[j].count)
			{
				continue;
			}
			//先在一组里面找到有事件的那个
			DWORD res_wait = WSAWaitForMultipleEvents(fd_es_set[j].count,
													  fd_es_set[j].all_event,
													  FALSE,
													  0,
													  FALSE);
			if (WSA_WAIT_FAILED == res_wait)//出错了
			{
				printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
				continue;
			}
			if (WSA_WAIT_TIMEOUT == res_wait)
			{
				continue;
			}
			DWORD index = res_wait - WSA_WAIT_EVENT_0;//先得到第一个触发事件的客户端的下标

			for (int i = index; i < fd_es_set[j].count; i++)
			{
				//一次只询问一个
				DWORD res_wait_event = WSAWaitForMultipleEvents(1,
																&fd_es_set[j].all_event[i],
																FALSE,
																0,/*不等待,有没有信号都立即返回*/
																FALSE);
				if (WSA_WAIT_FAILED == res_wait_event)//出错了
				{
					printf("WSAWaitForMultipleEvents error, error_code:%d\n", WSAGetLastError());
					continue;
				}
				//超时
				if (WSA_WAIT_TIMEOUT == res_wait_event)
				{
					//printf("WSAWaitForMultipleEvents timeout\n");
					continue;
				}

				//等到下标对应的具体操作
				WSANETWORKEVENTS network_events;
				int res_enum_events = WSAEnumNetworkEvents(fd_es_set[j].all_sock[i],
														   fd_es_set[j].all_event[i],
														   &network_events);
				if (SOCKET_ERROR == res_enum_events)
				{
					printf("WSAEnumNetworkEvents error, error_code:%d\n", res_enum_events);
					break;
				}

				/*事件分类处理*/
				//处理FD_ACCEPT
				if (network_events.lNetworkEvents & FD_ACCEPT)
				{
					if (0 == network_events.iErrorCode[FD_ACCEPT_BIT])
					{
						//正常处理
						SOCKET socket_client = accept(fd_es_set[j].all_sock[i], NULL, NULL);
						if (INVALID_SOCKET == socket_client)
						{
							continue;
						}
						//为客户端创建事件对象
						WSAEVENT wsa_client_event = WSACreateEvent();
						if (WSA_INVALID_EVENT == wsa_client_event)
						{
							closesocket(socket_client);
							continue;
						}
						//将客户端投递给系统 处理FD_READ FD_CLOSE FD_WRITE
						int res_client_event_select = WSAEventSelect(socket_client,
																	 wsa_client_event,
																	 FD_READ | FD_CLOSE | FD_WRITE);
						if (SOCKET_ERROR == res_client_event_select)
						{
							printf("client_event_select error,error_code:%d\n", WSAGetLastError());
							//关闭、释放事件
							BOOL colse_event_flag = WSACloseEvent(wsa_client_event);
							if (TRUE == colse_event_flag)
							{
								printf("wsa_client_event close success\n");
							}
							else if (FALSE == colse_event_flag)
							{
								printf("wsa_client_event close failed,error_code:%d\n", WSAGetLastError());
							}
							//关闭socket
							closesocket(socket_client);
							//关闭网络库
							WSACleanup();//关闭网络库
							return -1;
						}

						for (int k = 0; k < 20; k++)
						{
							if (fd_es_set[k].count < 64)
							{
								//装进结构体
								fd_es_set[k].all_sock[fd_es_set[k].count] = socket_client;
								fd_es_set[k].all_event[fd_es_set[k].count] = wsa_client_event;
								fd_es_set[k].count++;
								break;
							}
						}

						printf("accept event\n");
					}
					else
					{
						printf("network_events FD_ACCEPT | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_ACCEPT_BIT]);
						continue;
					}
				}

				//处理FD_WRITE
				if (network_events.lNetworkEvents & FD_WRITE)
				{
					if (0 == network_events.iErrorCode[FD_WRITE_BIT])
					{
						//初始化
						//int res_send = send(fd_es_set.all_sock[index], "connect success",
						//					sizeof("connect success") - 1, 0);//sizeof()包括'\0'
						int res_send = send(fd_es_set[j].all_sock[i], "connect success",
											strlen("connect success"), 0);//strlen()不包括'\0'
						if (SOCKET_ERROR == res_send)
						{
							printf("send error, error_code:%d\n", WSAGetLastError());
							continue;
						}
						printf("write event\n");
					}
					else
					{
						printf("network_events FD_WRITE | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_WRITE_BIT]);
						continue;
					}
				}

				//处理FD_READ
				if (network_events.lNetworkEvents & FD_READ)
				{
					if (0 == network_events.iErrorCode[FD_READ_BIT])
					{
						char recv_buf[1500] = { 0 };
						int res_recv = recv(fd_es_set[j].all_sock[i], recv_buf, 1499, 0);
						if (SOCKET_ERROR == res_recv)
						{
							printf("recv error, error_code:%d\n", WSAGetLastError());
							continue;
						}
						printf("recv data:%s\n", recv_buf);
					}
					else
					{
						printf("network_events FD_READ | socket error, error_code:%d\n",
							   network_events.iErrorCode[FD_READ_BIT]);
					}
				}

				//处理FD_CLOSE
				if (network_events.lNetworkEvents & FD_CLOSE)
				{
					printf("client close\n");
					printf("network_events FD_CLOSE | socket error, error_code:%d\n",
						   network_events.iErrorCode[FD_CLOSE_BIT]);
					//清理下线客户端 的 套接字 和 事件
					//清理套接字
					closesocket(fd_es_set[j].all_sock[i]);
					fd_es_set[j].all_sock[i] = fd_es_set[j].all_sock[fd_es_set[j].count - 1];
					//清理事件
					WSACloseEvent(fd_es_set[j].all_event[i]);
					fd_es_set[j].all_event[i] = fd_es_set[j].all_event[fd_es_set[j].count - 1];
					//数量减1
					fd_es_set[j].count--;
				}

			}
		}
	}

	/*释放所有的socket*/
	for (int j = 0; j < 20; j++)
	{
		for (int i = 0; i < fd_es_set[j].count; i++)
		{
			closesocket(fd_es_set[j].all_sock[i]);
			WSACloseEvent(fd_es_set[j].all_event[i]);
		}
	}
	
	/*关闭网络库*/
	WSACleanup();//关闭网络库
	printf("\n");
	system("pause");
	return 0;
}

select模型服务端DEMO

4 select模型与event_select模型比较

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值