windows TCP/IP 网络编程(五)5种windows网络模型(4) 重叠IO模型(a)事件通知

在这里插入图片描述
本文思维导图

1 重叠IO介绍

在这里插入图片描述
重叠IO两种反馈方式: ①事件通知 ②完成例程

2 重叠IO逻辑 和 性能

在这里插入图片描述

3 事件通知实现逻辑

在这里插入图片描述

4 创建socket

在这里插入图片描述

5 重叠IO

5.1 投递异步接收链接请求

在这里插入图片描述

5.2 WSARecv

在这里插入图片描述

5.3 WSASend

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

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


#define MAX_COUNT 1024
#define MAX_RECV_COUNT 1024

SOCKET all_socket[MAX_COUNT];
OVERLAPPED all_olp[MAX_COUNT];
int count = 0;
char recv_buf[MAX_RECV_COUNT];//接收缓冲区

void Clear()
{
	for (int i = 0; i < count; i++)
	{
		closesocket(all_socket[i]);
		WSACloseEvent(all_olp[i].hEvent);
	}
}


BOOL WINAPI fun(DWORD dwCtrlType)
{
	switch (dwCtrlType)
	{
	case CTRL_CLOSE_EVENT:
		//释放所有socket
		Clear();

		break;
	}
	return TRUE;
}

int PostAccept();
int PostRecv(int index);
int PostSend(int index);


int main(int argc, char* argv[])
{
	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 socketServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	//int a = WSAGetLastError();
	if (INVALID_SOCKET == socketServer)
	{
		int a = WSAGetLastError();
		//清理网络库
		WSACleanup();
		return 0;
	}

	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 a = ~0;
	if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr *)&si, sizeof(si)))
	{
		//出错了
		int a = WSAGetLastError();
		//释放
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	if (SOCKET_ERROR == listen(socketServer, SOMAXCONN))
	{
		//出错了
		int a = WSAGetLastError();
		//释放
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	all_socket[count] = socketServer;
	all_olp[count].hEvent = WSACreateEvent();
	count++;

	if (0 != PostAccept())
	{
		Clear();
		//清理网络库
		WSACleanup();
		return 0;
	}


	while (1)
	{
		for (int i = 0; i < count; i++)
		{
			int nRes = WSAWaitForMultipleEvents(1, &(all_olp[i].hEvent), FALSE, 0, FALSE);
			if (WSA_WAIT_FAILED == nRes || WSA_WAIT_TIMEOUT == nRes)
			{
				continue;
			}

			//有信号了
			DWORD state;
			DWORD dw_flag;
			BOOL b_flag = WSAGetOverlappedResult(all_socket[i], &all_olp[i], &state, TRUE, &dw_flag);

			//信号置空
			WSAResetEvent(all_olp[i].hEvent);

			if (FALSE == b_flag)
			{
				int a = WSAGetLastError();
				if (10054 == a)
				{
					printf("force close\n");
					//客户端下线
					//关闭
					closesocket(all_socket[i]);
					WSACloseEvent(all_olp[i].hEvent);
					//从数组中删掉
					all_socket[i] = all_socket[count - 1];
					all_olp[i] = all_olp[count - 1];
					//循环控制变量-1
					i--;
					//个数减-1
					count--;
				}
				continue;
			}
			//成功
			if (0 == i)
			{
				PostSend(count);
				printf("accept\n");
				//接收链接完成了
				//投递recv
				PostRecv(count);
				//根据情况投递send
				//客户端适量++
				count++;
				//投递accept
				PostAccept();
				continue;
			}

			if (0 == state)
			{
				printf("close\n");
				//客户端下线
				//关闭
				closesocket(all_socket[i]);
				WSACloseEvent(all_olp[i].hEvent);
				//从数组中删掉
				all_socket[i] = all_socket[count - 1];
				all_olp[i] = all_olp[count - 1];
				//循环控制变量-1
				i--;
				//个数减-1
				count--;
				continue;
			}

			if (0 != state)
			{
				//发送 或者 接收成功了
				if (recv_buf[0] != 0)
				{
					//recv
					//打印信息
					printf("%s\n", recv_buf);
					memset(recv_buf, 0, MAX_RECV_COUNT);
					//根据情况投递send
					//对自己投递接收
					PostRecv(i);
				}
				else
				{
					//send
					printf("发送完毕\n");
				}
			}
		}
	}



	closesocket(socketServer);
	//清理网络库
	WSACleanup();
	
	printf("\n");
	system("pause");
	return 0;
}


int PostAccept()
{
	all_socket[count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	all_olp[count].hEvent = WSACreateEvent();

	char str_buf[1024] = { 0 };
	DWORD recv_cnt;

	BOOL bRes = AcceptEx(all_socket[0], all_socket[count], str_buf, 0, sizeof(struct sockaddr_in) + 16,
						 sizeof(struct sockaddr_in) + 16, &recv_cnt, &all_olp[0]);

	if (TRUE == bRes)
	{
		//立即完成了
		//投递recv
		PostRecv(count);
		//根据情况投递send
		//客户端适量++
		count++;
		//投递accept
		PostAccept();
		return 0;
	}
	else
	{
		int a = WSAGetLastError();
		if (ERROR_IO_PENDING == a)
		{
			//延迟处理
			return 0;
		}
		else
		{
			return a;
		}
	}
}

int PostRecv(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = recv_buf;
	wsabuf.len = 1024;

	DWORD recv_count;
	DWORD flag = 0;
	int nRes = WSARecv(all_socket[index], &wsabuf, 1, &recv_count, &flag, &all_olp[index], NULL);

	if (0 == nRes)
	{
		//立即完成的
		//打印信息
		printf("%s\n", wsabuf.buf);
		memset(recv_buf, 0, MAX_RECV_COUNT);
		//根据情况投递send
		//对自己投递接收
		PostRecv(index);
		return 0;
	}
	else
	{
		int a = WSAGetLastError();
		if (ERROR_IO_PENDING == a)
		{
			//延迟处理
			return 0;
		}
		else
		{
			return a;
		}
	}
}

int PostSend(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = "你好";
	wsabuf.len = MAX_RECV_COUNT;

	DWORD send_count;
	DWORD flag = 0;
	int nRes = WSASend(all_socket[index], &wsabuf, 1, &send_count, flag, &all_olp[index], NULL);

	if (0 == nRes)
	{
		//立即完成的
		//打印信息
		printf("send成功\n");

		return 0;
	}
	else
	{
		int a = WSAGetLastError();
		if (ERROR_IO_PENDING == a)
		{
			//延迟处理
			return 0;
		}
		else
		{
			return a;
		}
	}
}


OverLappedEventServer SEMO

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值