window下IOCP模型

1 iocp回声服务器

-------------------------------------ThreadPool.h----------------------------------------
//线程池是iocp回声服务器的基础
#pragma once
#include <atomic>
#include <process.h>
#include <vector>
#include <mutex>
#include <WinSock2.h>
#include <atlstr.h>
#include <iostream>
typedef int (*FUNCTYPE)(void*);
class ThreadWorker {
public:
	ThreadWorker() : func(NULL), arg(arg) {};
	ThreadWorker(FUNCTYPE f, void* arg = NULL) : func(f), arg(arg) {}
	ThreadWorker(const ThreadWorker& worker) {
		func = worker.func;
		arg = worker.arg;
	}
	ThreadWorker& operator=(const ThreadWorker& worker) {
		if (this != &worker) {
			func = worker.func;
			arg = worker.arg;
		}
		return *this;
	}

	int operator()(void* arg) {
		if (IsValid()) {
			return func(arg);
		}
		return -1;
	}
	bool IsValid() const {
		return (func != NULL);
	}

public:
	FUNCTYPE func;
	void* arg;
};


class MyThread
{
public:
	MyThread() {
		m_hThread = NULL;
		m_bStatus = false;
	}
	~MyThread() {

	}
	/*
	* 判断线程状态:
	* 返回true表示有效 返回false表示线程异常或者已经终止
	*/
	bool IsValid() {
		if (m_hThread == NULL || (m_hThread == INVALID_HANDLE_VALUE))return false;
		return WaitForSingleObject(m_hThread, 0) == WAIT_TIMEOUT;
	}
	/*
	* 启动线程:
	* 返回true表示成功 返回false表示失败
	*/
	bool Start() {
		m_bStatus = true;
		m_hThread = (HANDLE)_beginthread(&MyThread::ThreadEntry, 0, this);
		if (!IsValid()) {
			m_bStatus = false;
		}
		return m_bStatus;
	}
	/*
	* 关闭线程:
	* 返回true表示成功 返回false表示失败
	*/
	bool Stop() {
		if (m_bStatus == false)return true;
		m_bStatus = false;
		bool ret = WaitForSingleObject(m_hThread, INFINITE) == WAIT_OBJECT_0;
		UpdateWorker();
		return ret;
	}
	void UpdateWorker(const ::ThreadWorker& worker = ::ThreadWorker()) {
		if (m_worker.load() != NULL && m_worker.load() != &worker) {
			::ThreadWorker* pWorker = m_worker.load();
			m_worker.store(NULL);
			delete pWorker;
		}
		if (!worker.IsValid()) {
			m_worker.store(NULL);
			return;
		}
		m_worker.store(new ::ThreadWorker(worker));
	}
	/*
	* 检测当前线程是否被分配任务:
	* true:分配;false:未分配
	*/
	bool IsIdle() {
		if (m_worker == NULL)return true;
		return !m_worker.load()->IsValid();
	}

private:
	/*
	* 开启线程:
	* 调用系统API,开启一个系统线程
	*/
	static void ThreadEntry(void* arg) {
		MyThread* thiz = (MyThread*)arg;
		if (thiz) {
			thiz->ThreadWorker();
		}
		_endthread();
	}
	/*
	* 执行线程:
	* 如果m_worker一直没有被分配任务,则一直循环,不会执行
	* 一旦被分配任务,就会执行函数
	*/
	void ThreadWorker() {
		while (m_bStatus) {
			if (m_worker == NULL) {
				Sleep(1);
				continue;
			}
			::ThreadWorker worker = *m_worker.load();
			if (worker.IsValid()) {
				int ret = worker(worker.arg);
				if (ret == -1) {
					std::cout << "thread found warning" << std::endl;
				}
				else {
					m_worker.store(NULL);
				}
			}
			else {
				Sleep(1);
			}
		}
	}
private:
	HANDLE m_hThread;//线程句柄
	bool m_bStatus;//线程当前状态
	std::atomic<::ThreadWorker*> m_worker;//存放一个线程类,主要包括函数

};

class MyThreadPool
{
public:
	MyThreadPool(size_t size) {
		m_threads.resize(size);
		for (size_t i = 0; i < size; i++)
			m_threads[i] = new MyThread();
	}
	MyThreadPool() {}
	~MyThreadPool() {
		Stop();
		for (size_t i = 0; i < m_threads.size(); i++)
		{
			MyThread* pThread = m_threads[i];
			m_threads[i] = NULL;
			delete pThread;
		}

		m_threads.clear();
	}
	//激活线程池
	bool Invoke() {
		bool ret = true;
		for (size_t i = 0; i < m_threads.size(); i++) {
			if (m_threads[i]->Start() == false) {
				ret = false;
				break;
			}
		}
		if (ret == false) {
			for (size_t i = 0; i < m_threads.size(); i++) {
				m_threads[i]->Stop();
			}
		}
		return ret;
	}
	void Stop() {
		for (size_t i = 0; i < m_threads.size(); i++) {
			m_threads[i]->Stop();
		}
	}

	//返回-1 表示分配失败,所有线程都在忙 大于等于0,表示第n个线程分配来做这个事情
	int DispatchWorker(const ThreadWorker& worker) {
		int index = -1;
		m_lock.lock();
		for (size_t i = 0; i < m_threads.size(); i++) {
			if (m_threads[i] != NULL && m_threads[i]->IsIdle()) {
				m_threads[i]->UpdateWorker(worker);
				index = i;
				break;
			}
		}
		m_lock.unlock();
		return index;
	}

	bool CheckThreadValid(size_t index) {
		if (index < m_threads.size()) {
			return m_threads[index]->IsValid();
		}
		return false;
	}
public:
	std::mutex m_lock;
	std::vector<MyThread*> m_threads;
};
----------------------------------------iocpServer.cpp-----------------------------------
#include"ThreadPool.h"
#include <WinSock2.h>
#include <iostream>
#include <map>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
MyThreadPool pool(10);
#define BUF_SIZE 100
#define READ  1
#define WRITE 2
class ClientMessage {    //客户端信息
public:
	SOCKET hclientSocket;
	SOCKADDR_IN clientAddr;
};

class MyOverlapped {
public:
	MyOverlapped() {
		memset(&m_overlapped, 0, sizeof(m_overlapped));
		m_wsabuffer.len = BUF_SIZE;
		m_wsabuffer.buf = buffer;
	}
public:
	OVERLAPPED m_overlapped;
	int m_operator;//操作 1 读;2 写
	char buffer[BUF_SIZE];//缓冲区
	ThreadWorker m_worker;//处理函数
	ClientMessage client;
	WSABUF m_wsabuffer;
};
int ReadyReadThread(void* arg) {
	DWORD flags = 0;
	MyOverlapped* overlap = (MyOverlapped*)arg;
	memset(&(overlap->m_overlapped), 0, sizeof(OVERLAPPED));
	overlap->m_operator = WRITE;
	//客户端socket 缓存数组地址  数组长度  保存实际字节数变量的地址  数据传输特性   时间状态  Routine函数
	WSASend(overlap->client.hclientSocket, &(overlap->m_wsabuffer), 1, NULL, 0, &(overlap->m_overlapped), NULL);
	cout << "发送完数据" << endl;
	return 0;
}
int ReadyWriteThread(void* arg) {
	DWORD flags = 0;
	MyOverlapped* lpoverlap = (MyOverlapped*)arg;
	MyOverlapped* overlap = new MyOverlapped();
	overlap->m_operator = READ;
	overlap->client = lpoverlap->client;
	WSARecv(overlap->client.hclientSocket, &(overlap->m_wsabuffer), 1, NULL, &flags, &(overlap->m_overlapped), NULL);
	cout << "继续准备接受数据" << endl;
	delete lpoverlap;
	return 0;
}
unsigned WINAPI EchoThreadMain(LPVOID pComPort)
{
	cout << "线程 NO.  " << GetCurrentThreadId() << endl;
	cout << "EchoThreadMain() 初始化" << endl;
	HANDLE hComPort = (HANDLE)pComPort;
	SOCKET sock;
	DWORD bytesTrans = 0;
	ClientMessage* handleInfo;
	MyOverlapped* overlap;
	DWORD flags = 0;
	while (1) {
		//在操作队列中获取IO完成的客户端信息 
		GetQueuedCompletionStatus(hComPort, &bytesTrans, (PULONG_PTR)&handleInfo, (LPOVERLAPPED*)&overlap, INFINITE);
		if (bytesTrans != 0) {
			sock = handleInfo->hclientSocket;
			if (overlap->m_operator == READ) { //判断客户端是读还是写
				cout << "准备好已读!" << endl;
				cout << overlap->buffer << endl;
				overlap->m_wsabuffer.len = bytesTrans;
				while (1) {
					if (pool.DispatchWorker(ThreadWorker(&ReadyReadThread, overlap)) != -1) {
						break;
					}Sleep(100);
				}
			}
			else {
				cout << "准备好已写!" << endl;
				while (1) {
					if (pool.DispatchWorker(ThreadWorker(&ReadyWriteThread, overlap)) != -1) {
						break;
					}Sleep(100);
				}
			}
		}
	}
	return 0;
}

int main() {
	pool.Invoke();
	WSADATA wsadata;
	HANDLE hComPort; //完成端口句柄
	MyOverlapped* overlap;  //ioMessage
	ClientMessage* handleInfo;//key
	SOCKET serverSocket;
	SOCKADDR_IN serverAddr;
	DWORD recvBytes, flags = 0;
	//1.初始化套接字
	if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
		cout << "WSAStartup() error" << endl;
	//2.创建iocp对象(第二个参数为0,所以是新建的一个iocp),最后一个参数为0 创建和CPU核数相同的线程 返回NULL即为创建失败
	hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	if (hComPort == NULL) return 0;
	for (int i = 0; i < 3; i++) {
		_beginthreadex(NULL, 0, EchoThreadMain, (LPVOID)hComPort, 0, NULL);
	}

	//3.创建服务器的监听套接字
	serverSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (serverSocket == INVALID_SOCKET)
		cout << "socket()  error" << endl;

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddr.sin_port = htons(8000);

	if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
		cout << "bind () error" << endl;

	listen(serverSocket, 5);
	cout << "服务器启动成功!" << endl;
	//4.开始监听
	while (1) {
		SOCKET clientSocket;
		SOCKADDR_IN clientAddr;
		int addrLen = sizeof(clientAddr);
		cout << "wait connect!" << endl;
		clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &addrLen);
		if (clientSocket != INVALID_SOCKET) cout << "已有客户端连接:" << clientSocket << endl;
		//(1)为该socket增加key->handleInfo
		handleInfo = new ClientMessage(); 
		handleInfo->hclientSocket = clientSocket;  
		memcpy(&(handleInfo->clientAddr), &clientAddr, addrLen);  
		//(2)加入完成端口
		CreateIoCompletionPort((HANDLE)clientSocket, hComPort, (DWORD)handleInfo, 0);//绑定一个客户端socket给完成端口
		//(3)准备接收
		overlap = new MyOverlapped();  //创建事件对象等捆绑信息的句柄
		overlap->m_operator = READ;
		overlap->client = *handleInfo;
		WSARecv(handleInfo->hclientSocket, &(overlap->m_wsabuffer), 1, &recvBytes, &flags, &(overlap->m_overlapped), NULL);//异步等待接收客户端信息
		//参数:1重叠IO套接字 2保存接受信息的结构体数组 3第二个参数数组的长度     4保存接受消息大小的变量地址 5设置或读取传输特性的消息
		//        6事件对象的状态    7Routine函数地址
	}
}

2 iocp服务器创建步骤

注:(只映射和客户端通信的socket,暂时不考虑服务器监听的socket,因此socket要么准备好读,要么准备好写)

1.创建一个完成端口

2.开启一个(多个)线程来获取队列完成状态,也就是判断完成端口中哪些socke准备好读or写(额外开启线程来处理读写操作)

3.服务器创建监听socket检测客户端连接

4.检测到客户端连接后,将其socket加入到完成端口

iocp为什么采用线程池?

如果服务器每接入一个用户就开启一个线程为其服务,会大大增加服务器的负荷,iocp只有在socke确实需要操作才会额外开启线程,并且线程池可以控制服务器最大开启线程数量

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值