【Windows网络编程】重叠IO网络模型

//把数据从网卡复制到程序的buffer,但是也要时间。。重叠io就是解决这个问题
#include <WinSock2.h>
#include <stdio.h>
#define  PORT 6000
#define  MSGSIZE 1024
#pragma  comment (lib,"Ws2_32.lib")
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;
}
//单io操作。。buf。。
typedef struct
{
	WSAOVERLAPPED overlap;     //第一个成员。重叠io,必须用OVERLAPPED
	WSABUF buffer;					//发送长度或者接收的时候允许的最大长度
	char szMessage[MSGSIZE];
	DWORD NumberOfBytesRecvd;   //保存接收到的字节数
	DWORD Flags;				//保存操作类型。。收。。发。。
}PER_IO_OPERATION_DATA,  *LPPER_IO_OPERATION_DATA;

int g_iTotalConn = 0;

SOCKET g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];
LPPER_IO_OPERATION_DATA g_pPerIODataArr[MAXIMUM_WAIT_OBJECTS];


DWORD WINAPI WorkerThread(LPWORD);
void Cleanup(int);

int main()
{
	SOCKET sListen, sClient;
	SOCKADDR_IN local, client;
	DWORD dwThreadId;
	int iaddrSize = sizeof(SOCKADDR_IN);
	//初始化windowa socket库
	WinSockInit();
	//创建监听socket
	sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //默认设置WSA_FLAG_OVERLAPPED
	//绑定
	local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	local.sin_family = AF_INET;
	local.sin_port = htonl(PORT);
	bind(sListen, (struct sockaddr*)&local, sizeof(SOCKADDR_IN));
	//监听
	listen(sListen, 3);
	//创建工作者线程
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkerThread, NULL, 0, &dwThreadId);
	while (TRUE)
	{
		//接受连接
		sClient = accept(sListen, (struct sockaddr*)&client, &iaddrSize);
		printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
		g_CliSocketArr[g_iTotalConn] = sClient;

		//分配一个单io操作 数据结构
		g_pPerIODataArr[g_iTotalConn] = (LPPER_IO_OPERATION_DATA)HeapAlloc(
			GetProcessHeap(),
			HEAP_ZERO_MEMORY,
			sizeof(PER_IO_OPERATION_DATA));

		g_pPerIODataArr[g_iTotalConn]->buffer.len = MSGSIZE;
		g_pPerIODataArr[g_iTotalConn]->buffer.buf = g_pPerIODataArr[g_iTotalConn]->szMessage;
		g_CliEventArr[g_iTotalConn] = g_pPerIODataArr[g_iTotalConn]->overlap.hEvent = WSACreateEvent();
		//g_pPerIODataArr[g_iTotalConn].Flags = 1;
		//开始一个异步操作-不会阻塞程序。。告诉小秘按结构体进行数据操作
		WSARecv(
			g_CliSocketArr[g_iTotalConn],
			&g_pPerIODataArr[g_iTotalConn]->buffer,
			1,
			&g_pPerIODataArr[g_iTotalConn]->NumberOfBytesRecvd,
			&g_pPerIODataArr[g_iTotalConn]->Flags, &g_pPerIODataArr[g_iTotalConn]->overlap,
			NULL);
		//WSARecv的参数都有一个Overlapped参数,我们可以假设是我们的WSARecv这样的操作绑定到这个重叠结构上
		//提交一个请求,而不是将操作立即完成,其他事情交给重叠结构去做,而其中重叠结构要与事件对象绑定在一起
		//这样我们调用完WSARecv以后就可以“坐享其成”,等重叠操作完成后,自然会有与之对应的的事件通知我们操作完成
		//然后我们就可以根据重叠操作的结果取得我们想要的数据了

		g_iTotalConn++;
	}

	closesocket(sListen);
	WSACleanup();
	return 0;
}
DWORD WINAPI WorkerThread(LPWORD lpParam)
{
	int ret, index;
	DWORD cbTransferred;
	while (TRUE)
	{
		//判断出一个重叠IO调用是否完成
		ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
		if (ret==WSA_WAIT_FAILED||ret==WSA_WAIT_TIMEOUT)
			continue;
		index = ret - WSA_WAIT_EVENT_0;
		WSAResetEvent(g_CliEventArr[index]);   //手动设置为未传信,
		WSAGetOverlappedResult(
			g_CliSocketArr[index],
			&g_pPerIODataArr[index]->overlap,
			&cbTransferred,
			TRUE,
			&g_pPerIODataArr[g_iTotalConn]->Flags); //判断该重叠调用成功还是失败
		if (cbTransferred == 0)
			Cleanup(index);  //客户端连接关闭
		else
		{
			//g_pPerIODataArr[index]->szMessage保存接收到的数据
			g_pPerIODataArr[index]->szMessage[cbTransferred] = '\0';
			send(g_CliSocketArr[index], g_pPerIODataArr[index]->szMessage,
				cbTransferred, 0);
			//进行另一个异步操作
			WSARecv(g_CliSocketArr[index],
				&g_pPerIODataArr[index]->buffer,
				1,
				&g_pPerIODataArr[index]->NumberOfBytesRecvd,
				&g_pPerIODataArr[index]->Flags,
				&g_pPerIODataArr[index]->overlap,
				NULL);
		}
	}
	return 0;
}
void Cleanup(int index)
{
	closesocket(g_CliSocketArr[index]);
	WSACloseEvent(g_CliEventArr[index]);
	HeapFree(GetProcessHeap(), 0, g_pPerIODataArr[index]);
	if (index < g_iTotalConn - 1)
	{
		g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
		g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
		g_pPerIODataArr[index] = g_pPerIODataArr[g_iTotalConn - 1];
	}
	g_pPerIODataArr[--g_iTotalConn] = NULL;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值