【Windows网络编程】EventSelect网络模型

//解决select模型工作者线程时间片未充分利用的问题
#include <winsock2.h>
#include <stdio.h>
#define PORT 6000
#pragma comment (lib,"Ws2_32.lib")
SOCKET ArrSocket[1024] = { 0 };
WSAEVENT ArrEvent[1024] = { 0 };
DWORD dwTotal = 0;
DWORD dwIndex = 0;
int ClientNums = 0;         //标记已经链接了多少个客户端
BOOL WinSockInit()
{
	WSADATA data = { 0 };
	if (WSAStartup(MAKEWORD(2, 2), &data))
		return FALSE;
	if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2){
		WSACleanup();
		return FALSE;
	}
	return TRUE;
}
//工作者线程 怎么实现 将监听的socket以及客户端通信的socket 同时进行监控?
//怎么来节省时间的?(相对select)
DWORD WINAPI ListentThreadProc(LPARAM lparam)
{
	char buf[1024] = { 0 };
	SOCKET sockClient = INVALID_SOCKET;  //用于accept临时使用的socket
	WSANETWORKEVENTS NetWorkEvent = { 0 };
	while (true){
		//ArrSocket[1];
		//数组内任意一个wsaevent有信号了,api就返回。。
		dwIndex = WSAWaitForMultipleEvents(dwTotal, ArrEvent, FALSE, 100, FALSE);
		if (dwIndex == WSA_WAIT_TIMEOUT){
			continue;
		}
		//如何知道是哪个socket出现了网络事件,deindex发生网络事件的socket数组下标
		WSAEnumNetworkEvents(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], ArrEvent[dwIndex - WSA_WAIT_EVENT_0], &NetWorkEvent);
	
		if (NetWorkEvent.lNetworkEvents&FD_ACCEPT){//如果第三位数据是1,代表有客户端进行连接
			if (NetWorkEvent.iErrorCode[FD_ACCEPT_BIT] != 0)
			{
				continue;
			}
			sockClient = accept(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], NULL, NULL);
			if (sockClient == INVALID_SOCKET)
				continue;
			//连接完成后,立即将客户端的socket保存到数据,同时新建event与socket建立关系
			WSAEVENT newEvent = WSACreateEvent();
			WSAEventSelect(sockClient, newEvent, FD_READ | FD_WRITE | FD_CLOSE);

			for (;;);//检查数组内是否有空值,如果有就保存。。
			ArrSocket[dwTotal] = sockClient;
			ArrEvent[dwTotal] = newEvent;
			++dwTotal;
			++ClientNums;
		}

		if (NetWorkEvent.lNetworkEvents&FD_READ)    //说明有客户端向服务器发送数据 但这个数据还只在网卡上 没有到达程序buffer
		{
			if (NetWorkEvent.iErrorCode[FD_READ_BIT] != 0)
			{
				continue;
			}
			recv(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, sizeof(buf), 0);
			printf("Recv:%s\n", buf);
			send(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, strlen(buf), 0);
		}

		if (NetWorkEvent.lNetworkEvents&FD_WRITE)   //说明程序-服务器准备向客户端发送信息了、、
		{
			if (NetWorkEvent.iErrorCode[FD_WRITE_BIT] != 0)
			{
				continue;
			}
			printf("Send somthing\n");
		}

		if (NetWorkEvent.lNetworkEvents&FD_CLOSE)   //表示有一个socket关闭了 是监听的还是通信的 不需要关心。。
		{
			if (NetWorkEvent.iErrorCode[FD_CLOSE_BIT] != 0)
			{
				continue;
			}
			closesocket(ArrSocket[dwIndex - WSA_WAIT_EVENT_0]);
			ArrSocket[dwIndex - WSA_WAIT_EVENT_0] = 0;
		}
	}
}
int main()
{
	WinSockInit();
	SOCKET sockListen = INVALID_SOCKET;//服务器监听的socket
	sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sockListen == INVALID_SOCKET)
	{
		printf("Creat Socket Error");
		return -1;
	}
	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_addr.S_un.S_addr = INADDR_ANY;
	service.sin_port = htons(PORT);

	if (bind(sockListen, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR)
	{
		printf("Bind Failed\n");
		return -1;
	}


	//进行event select特有的操作
	WSAEVENT ListenEvent = WSACreateEvent();
	//把WSAEVENT与一个socket进行绑定没 告诉绑定的对象需要关注的事件有哪些
	WSAEventSelect(sockListen, ListenEvent, FD_ACCEPT | FD_CLOSE);//仅关注两个事件,有客户端进行连接,需要关闭服务器监听的socket
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ListentThreadProc, NULL, NULL, NULL);//创建一个子进程,用子进程来处理所有的socket上的事件

	if (listen(sockListen, SOMAXCONN) == SOCKET_ERROR){
		printf("Listen Error\n");
		return -1;
	}
	ArrSocket[dwTotal] = sockListen;
	ArrEvent[dwTotal] = ListenEvent;
	++dwTotal;//标识总共有多少个用户已经连接 到这里数组保存的socket只有一个

	system("pause");
	if (sockListen != INVALID_SOCKET)
	{
		closesocket(sockListen);
	}
	WSACleanup();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值