windows io完成端口实例

#pragma once
#include <WinSock2.h>    
#pragma comment(lib,"ws2_32.lib") 
 
#define DATA_BUFSIZE               512
enum { READ, WRITE };
 
typedef struct io_operation_data
{
	OVERLAPPED overlapped;
	WSABUF databuf;
	CHAR buffer[DATA_BUFSIZE];
	BYTE type;
	DWORD length;
}IO_OPERATION_DATA;
 
class IOCP
{
public:
	IOCP(SOCKET s, SOCKADDR_IN sin);
	virtual ~IOCP();
	BOOL recvAsynData();
	BOOL sendAsynData();
public:
	SOCKET m_s;
	SOCKADDR_IN m_sin;
	IO_OPERATION_DATA m_io;
};
#include "IOCP.h"
#include <process.h>
#include <list>
std::list<IOCP*> iocpList;
HANDLE hComPort = NULL;
 
IOCP::IOCP(SOCKET s, SOCKADDR_IN sin)
{
	m_s = s;
	m_sin = sin;
}
 
IOCP::~IOCP()
{
}
 
BOOL IOCP::recvAsynData()
{
	DWORD flags = 0L;
	DWORD length = 0L;
	ZeroMemory(&m_io, sizeof (IO_OPERATION_DATA));
	m_io.type = READ;
	m_io.databuf.buf = m_io.buffer;
	m_io.databuf.len = DATA_BUFSIZE;
	if (WSARecv(m_s, &m_io.databuf, 1, &length, &flags, &m_io.overlapped, NULL) == SOCKET_ERROR){
		if (ERROR_IO_PENDING != WSAGetLastError()){
			return FALSE;
		}
	}
	return TRUE;
}
 
BOOL IOCP::sendAsynData()
{
	DWORD flags = 0L;
	DWORD length = 0L;
	m_io.type = WRITE;
	m_io.databuf.buf = m_io.buffer;
	m_io.databuf.len = strlen(m_io.buffer);
	if (WSASend(m_s, &m_io.databuf, 1, &length, flags, (LPOVERLAPPED)&m_io, NULL) == SOCKET_ERROR){
		if (ERROR_IO_PENDING != WSAGetLastError()){
			return FALSE;
		}
	}
	return TRUE;
}
 
void eraseIocp(IOCP* iocp)
{
	std::list<IOCP*>::iterator iter = iocpList.begin();
	for (; iter != iocpList.end(); ++iter){
		if ((*iter) == iocp){
			iocpList.erase(iter);
			break;
		}
	}
}
 
unsigned int __stdcall service_work_thread(void* context)
{
	DWORD dwIoSize;
	IOCP* iocp;
	LPOVERLAPPED lpoverlapped;
	while (true){
		Sleep(2000);
		dwIoSize = -1;
		lpoverlapped = NULL;
		iocp = NULL;
		BOOL ret = GetQueuedCompletionStatus(hComPort, &dwIoSize, (LPDWORD)&iocp, &lpoverlapped, INFINITE);
		if (iocp == NULL && lpoverlapped == NULL){//PostQueuedCompletionStatus
			break;
		}
		if (!ret){
			printf("err\n");
			DWORD dwIoErr = GetLastError();
			if (dwIoErr == WAIT_TIMEOUT){
				continue;
			}
			else if (NULL != lpoverlapped){
				eraseIocp(iocp);
			}
			else{
				break;
			}
		}
		else{
			if (0 == dwIoSize){
				eraseIocp(iocp);
				continue;
			}
			IO_OPERATION_DATA* pIO = CONTAINING_RECORD(lpoverlapped, IO_OPERATION_DATA, overlapped);
			switch (pIO->type){
			case READ:
				iocp->m_io.length = dwIoSize;
				iocp->m_io.buffer[iocp->m_io.length] = '\0';
				//printf("read:%s\n", iocp->m_io.buffer);
				char buffer[64];
				sprintf_s(buffer, 64, "hi iocp msg.(%d)", iocp->m_s);
				strcpy_s(iocp->m_io.buffer, 64, buffer);
				iocp->sendAsynData();
				break;
			case WRITE:
				//printf("write:%s\n",iocp->m_io.buffer);
				pIO->length = 0;
				if (FALSE == iocp->recvAsynData()){
					eraseIocp(iocp);
				}
				break;
			default: break;
			}
		}
	}
	return 0;
}
 
int createIoCompletionPort(int port)
{
	SYSTEM_INFO systemInfo;
	HANDLE hThreadHandle[64];
	//创建完成端口
	if ((hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL){
		return -1;
	}
	GetSystemInfo(&systemInfo);
	DWORD cpuNum = systemInfo.dwNumberOfProcessors;
	//线程池
	for (unsigned int i = 0; i < cpuNum * 2; ++i){
		if ((hThreadHandle[i] = (HANDLE)_beginthreadex(NULL, 0, service_work_thread, hComPort, 0, NULL)) == NULL){
			return -1;
		}
	}
	int ret = 0;
	WSADATA wsaData;
	if ((ret = WSAStartup(0x0202, &wsaData)) != 0){
		return -1;
	}
	SOCKET sListen = INVALID_SOCKET;
	if ((sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET){
		WSACleanup();
		return -1;
	}
	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	sin.sin_port = htons(port);
	if (bind(sListen, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR){
		closesocket(sListen);
		WSACleanup();
		return -1;
	}
	if (listen(sListen, SOMAXCONN)){
		closesocket(sListen);
		WSACleanup();
		return -1;
	}
	SOCKET sAccept = INVALID_SOCKET;
	SOCKADDR_IN saddr_in;
	int length = sizeof(saddr_in);
	int total = 0;
	while (true){
		if ((sAccept = WSAAccept(sListen, (SOCKADDR*)&saddr_in, &length, NULL, 0)) == SOCKET_ERROR){
			break;
		}
		++total;
		if (total % 10 == 0){
			printf("accept client count(%d)\n", total);
		}
		IOCP* iocp = new IOCP(sAccept, saddr_in);
		iocpList.push_back(iocp);
		//绑定完成端口
		if (CreateIoCompletionPort((HANDLE)sAccept, hComPort, (DWORD)iocp, 0) == NULL){
			return -1;
		}
		if (!iocp->recvAsynData()){
			eraseIocp(iocp);
		}
	}
	//销毁线程池
	for (unsigned int i = 0; i < cpuNum * 2; ++i){
		PostQueuedCompletionStatus(hComPort, 0, NULL, NULL);
		CloseHandle(hThreadHandle[i]);
	}
	WaitForMultipleObjects(cpuNum * 2, hThreadHandle, TRUE, INFINITE);
 
	return 0;
}
 
int main(int argc, char* argv[])
{
	printf("io completion port.\n");
	createIoCompletionPort(8086);
	return 0;
}
#include <WinSock2.h>  
#pragma comment(lib,"ws2_32.lib")   
#include <stdio.h>  
 
/*
Date      |Change
-----------------------------------------
2017-7-31 |SOCKET TCP测试客户端
*/
void tcp_client()
{
	SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8086);
	sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	if (connect(sClient, (sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR){
		closesocket(sClient);
		return;
	}
	char buffer[1024];
	sprintf_s(buffer, 1024, "hi client msg.(%d)", sClient);
	//Sleep(1000);
	int ret = send(sClient, buffer, strlen(buffer), 0);
	ret = recv(sClient, buffer, sizeof(buffer), 0);
	buffer[ret] = '\0';
	//printf("%s\n", buffer);
	//closesocket(sClient);
}
 
int main(int argc, char* argv[])
{
	printf("tcp client.\n");
	WSADATA wsa;
	WSAStartup(MAKEWORD(2, 2), &wsa);
	int i = 500000;
	while (i--){
		tcp_client();
		//Sleep(3);
	}
	WSACleanup();
	return 0;
}

原文地址:
https://blog.csdn.net/qingdujun/article/details/76794765?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

关键函数
CreateIoCompletionPort
GetQueuedCompletionStatus
PostQueuedCompletionStatus

说明,其实io完成端口和io重叠很相似,
都是将异步的io 请求提交后 在某个地方等待 io完成的通知。
io重叠 调用 waitformultipleobjects 等待 发来的完成通知,再调用WSAGetOverlappedResult 获取该操作的 结果(成功或失败)

而io完成端口,只是将等待的通知放到了线程中,并且通过返回的参数获得操作的结果。调用的是GetQueuedCompletionStatus函数,这个函数会使线程阻塞,处于等待状态,并不进入睡眠。
这里的GetQueuedCompletionStatus 就类似于上面的waitformultipleobjects和WSAGetOverlappedResult 这两个函数,单数区别在于waitformultipleobjects 会使线程进入睡眠,而GetQueuedCompletionStatus不会使线程睡眠。
我们知道如果线程 频繁的在睡眠态和调度态切换的话,是会发费很多的cpu时间。而前者没有进入睡眠态,所以就比后者要高效些。

这就好比自旋锁比互斥锁的效率高一样,前者不会进入睡眠,后者会

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值