windows下高性能网络通信模型IOCP

#pragma once
#include<Windows.h>
#include<WinSock2.h>
#include<stdio.h>
#include<process.h>
#include<vector>
#pragma comment(lib,"ws2_32.lib")

//端口号
#define SERVER_PORT 9527


//IO操作类型
#define OP_READ 1
#define OP_WRITE 2
#define OP_ACCEPT 3
#define OP_END -1

#define BUF_SIZE 1024

//自定义结构,即“完成键”(单句柄数据)
typedef struct tagPER_HANDLE_DATA
{
	SOCKET Socket;
	SOCKADDR_STORAGE ClientAddr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

//单个I/O操作数据
typedef struct tagPer_IO_DATA
{
	OVERLAPPED Overlapped;
	WSABUF DataBuf;
	char buffer[1024];
	int BufferLen;
	int OperationType;            //IO操作类型

}PER_IO_DATA, *LPPER_IO_DATA;
#include"SelectServer.h"

SOCKET listenSock;
HANDLE completePort;

//线程句柄列表
std::vector<HANDLE> workthread;

//IO操作状态转换
//可以考虑这里使用状态模式
void ChangeHandleData(LPPER_IO_DATA perIOdata, int state)
{
	switch (state)
	{
	case OP_ACCEPT:
		perIOdata->OperationType = OP_READ;
		memset(&(perIOdata->Overlapped), 0, sizeof(OVERLAPPED));
		memset(&(perIOdata->DataBuf), 0, sizeof(WSADATA));
		perIOdata->DataBuf.buf = perIOdata->buffer;
		perIOdata->DataBuf.len = BUF_SIZE;
		break;
	case OP_READ:
		perIOdata->OperationType = OP_WRITE;
		memset(&(perIOdata->Overlapped), 0, sizeof(OVERLAPPED));
		//发送给客户端的数据
		char sendClientInfo[] = "sendClient";
		perIOdata->DataBuf.buf = sendClientInfo;
		perIOdata->DataBuf.len = strlen(sendClientInfo);
		break;
	case OP_WRITE:
		perIOdata->OperationType = OP_READ;
		memset(&(perIOdata->Overlapped), 0, sizeof(OVERLAPPED));
		memset(&(perIOdata->DataBuf), 0, sizeof(WSADATA));
		perIOdata->DataBuf.buf = perIOdata->buffer;
		perIOdata->DataBuf.len = BUF_SIZE;
		break;
	}
}

void SendHandleData(LPPER_IO_DATA perIoData, LPPER_HANDLE_DATA perHandleData)
{
	int result = 0;
	DWORD dwSize;
	DWORD nFlag = 0;
	if (perIoData->OperationType == OP_READ)
	{
		memset(&(perIoData->DataBuf), 0, sizeof(WSADATA));
		memset(&(perIoData->Overlapped), 0, sizeof(OVERLAPPED));
		if (SOCKET_ERROR == WSARecv(perHandleData->Socket, &(perIoData->DataBuf), 1, &dwSize, &nFlag, &(perIoData->Overlapped), NULL))
		{
			//如果调用失败
			//调用WSAGetLastError查看错误码
			printf("WSARecv() Failed:%d\n", WSAGetLastError());
			return;
		}
	}
	else if (perIoData->OperationType == OP_WRITE)
	{
		result = WSASend(perHandleData->Socket, &(perIoData->DataBuf), 1, &dwSize, nFlag, &(perIoData->Overlapped), NULL);
		if ((result == SOCKET_ERROR) && (::WSAGetLastError() != ERROR_IO_PENDING))
		{
			printf("WSASend() Failed:%d\n", ::WSAGetLastError());
			::closesocket(perHandleData->Socket);
		}
	}
	else if (perIoData->OperationType == OP_END)
	{
		::closesocket(perHandleData->Socket);
	}
}

//处理线程
UINT WINAPI WorkThread(LPVOID lpaameter)
{
	return 0;
}

int main()
{
	PER_HANDLE_DATA* perhandledata = NULL;
	WSADATA data = { 0 };
	if (::WSAStartup(MAKEWORD(2, 2), &data) != 0)
	{
		printf("Call WSAStartup Failed!");
		return 0;
	}

	listenSock = WSASocket(AF_INET, SOCK_STREAM,IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (listenSock == INVALID_SOCKET)
	{
		printf("Call socket Failed!");
		return 0;
	}

	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(SERVER_PORT);
	addr.sin_addr.S_un.S_addr = INADDR_ANY;

	if (::bind(listenSock, (sockaddr*)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
	{
		printf("Call bind Failed!");
		return 0;
	}

	if (::listen(listenSock, SOMAXCONN) == SOCKET_ERROR)
	{
		printf("Call listen Failed!");
		return 0;
	}

	SYSTEM_INFO si;
	::GetSystemInfo(&si);
	size_t threadCount = si.dwNumberOfProcessors * 2;
	//创建完成端口
	completePort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, threadCount);
	if (completePort == NULL)
	{
		printf("Create CompletionPort Failed!");
		return 0;
	}
	//创建处理线程
	for (size_t i = 0; i < threadCount; i++)
	{
		HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, WorkThread, completePort, 0, NULL);
		if (hThread)
		{
			workthread.push_back(hThread);
		}
	}

	int remotLen;
	SOCKADDR_IN adr;
	remotLen = sizeof(SOCKADDR_IN);
	while (TRUE)
	{
		SOCKET hAccept = ::accept(listenSock, (sockaddr*)&adr, &remotLen);
		if (hAccept == INVALID_SOCKET)
		{
			continue;
		}
		perhandledata = (PER_HANDLE_DATA*)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
		perhandledata->Socket = hAccept;
		memcpy(&perhandledata->ClientAddr, &adr, remotLen);
		if (perhandledata == NULL)
		{
			printf("perhandledata == null!");
			::closesocket(hAccept);
		}
		if (::CreateIoCompletionPort((HANDLE)hAccept, completePort, (DWORD)perhandledata, 0) == NULL)
		{
			//这里应该详细考察调用失败的原因
			::GlobalFree((HGLOBAL)perhandledata);
			::closesocket(hAccept);
			continue;
		}
		LPPER_IO_DATA perIodata = (LPPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
		ChangeHandleData(perIodata, OP_ACCEPT);
		SendHandleData(perIodata, perhandledata);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值