2009-06-04 15:44
//memorypool.h
#pragma
once
#include <iostream>
#include <list>
#include
<windows.h>
//关键区锁
class CLock
{
CRITICAL_SECTION _crisection;
public:
CLock()
{
InitializeCriticalSection( &_crisection );
}
~CLock()
{
DeleteCriticalSection( &_crisection );
}
void lock()
{
EnterCriticalSection(
&_crisection
);
}
void unlock()
{
LeaveCriticalSection(
&_crisection
);
}
};
//内存池模型:实质就是一个前向指针链表
template <class
particle>
class particle_allocator
{
enum
{
chunk_size
=1024
};
typedef
unsigned char byte;
struct
particle_list
{
particle
*_data;
particle_list
*_next;
};
std::list<particle *> _chunks;
particle_list* _free_list;
CLock
_guard;
public:
particle_allocator()
{
_free_list =
0;
_used_particle_number =
0;
_free_particle_number = 0;
}
~particle_allocator()
{
for(std::list<particle *>::iterator iter =
_chunks.begin();iter!=_chunks.end();++iter)
{
delete (*iter);
}
_chunks.clear();
while(_free_list)
{
particle_list *temp =
_free_list;
_free_list =
_free_list->_next;
delete temp;
}
}
particle*
alloc_particle()
{
_guard.lock();
byte
*momory;
particle_list* ¤t_list =
_free_list;
if(!current_list)
{
momory = new
byte[chunk_size*sizeof(particle)];
for(int i =
0;i<chunk_size;i++)
{
_chunks.push_front((particle *)(momory +
i*chunk_size));
}
for(int i =0;i<
chunk_size;i++,_free_particle_number++)
{
particle_list *newnode = new
particle_list;
newnode->_data = (particle *)(momory +
i*sizeof(particle));
newnode->_next =
current_list;
current_list =
newnode;
}
}
particle
*redata;
particle_list
*de_node =
current_list;
redata =
_free_list->_data;
current_list =
current_list->_next;
++_used_particle_number;
--_free_particle_number;
delete de_node;
_guard.unlock();
return new(redata) particle;
}
void free_particle(particle
*p)
{
particle *free_block
= p;
_guard.lock();
particle_list* ¤t_list =
_free_list;
particle_list *newnode = new
particle_list;
newnode->_data =
free_block;
newnode->_next =
current_list;
current_list =
newnode;
--_used_particle_number;
++_free_particle_number;
_guard.unlock();
}
void getallocator()
{
using namespace
std;
cout <<
"_used_particle_number is " << _used_particle_number << "
_free_particle_number is "<< _free_particle_number <<
endl;
}
public:
size_t _used_particle_number;
size_t
_free_particle_number;
};
//这个是内存分配优化类,由于服务器需要运行在一个相对静态的环境中。所以我第每次分配1024块某种结构的内存。用完继续分配1024块,使用的时候就在分配好的内存里边取一块,用完再归还回去。
//iocpsever.cpp
#include
<winsock2.h>
#include "memorypool.h"
#include
<Mswsock.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib,
"Mswsock.lib")
//
单句柄数据,每个连接(客户端)对应一个这样的结构。
//只有连接断开,或者服务器关闭的时候才释放
typedef struct
tagPER_HANDLE_DATA
{
SOCKET
Socket;
SOCKADDR_STORAGE
ClientAddr;
//
将和这个句柄关联的其他有用信息,尽管放在这里面吧
}PER_HANDLE_DATA,
*LPPER_HANDLE_DATA;
//
单I/O操作数据。每次收发数据的时候
//收发数据操作完成数之后释放。
//需要注意的是OVERLAPPED
Overlapped一定要放在最前
typedef struct
tagPER_IO_DATA
{
OVERLAPPED
Overlapped;
WSABUF
DataBuf;
char
buffer[1024];
DWORD
BufferLen;
int
OperationType;
SOCKET
Socket;
LPPER_HANDLE_DATA
lpSession;
}PER_IO_DATA, *LPPER_IO_DATA;
//操作标志
#define
OP_READ 0
#define
OP_WRITE 1
#define OP_ACCEPT
2
//连接数据内存池
particle_allocator<PER_IO_DATA>
g_per_io_data;
//数据收发内存池
particle_allocator<PER_HANDLE_DATA>
g_per_handle_data;
//完成线程
DWORD count =
0;
//保存当前连接数据指针
list<LPPER_HANDLE_DATA>
g_session;
//接受事件
HANDLE g_hAcceptExOverEvent =
NULL;
//工作线程
DWORD WINAPI ServerWorkerThread(LPVOID
lpParam);
using namespace std;
int main(void)
{
WSADATA
wsd;
SYSTEM_INFO
SystemInfo;
SOCKADDR_IN
InternetAddr;
SOCKET
Listen;
WSAStartup(MAKEWORD(2, 2),
&wsd);
//创建完成端口
HANDLE CompletionPort =
CreateIoCompletionPort(INVALID_HANDLE_value,
NULL,
0,
0);
//得到处理器数量
GetSystemInfo(&SystemInfo);
//经验公式:一般按公式创建工作线程
count =
2*(SystemInfo.dwNumberOfProcessors+1);
for (DWORD i = 0; i < count;
++i)
{
HANDLE
ThreadHandle;
ThreadHandle =
CreateThread(NULL,
0,
ServerWorkerThread,
CompletionPort,
0,
NULL);
CloseHandle(ThreadHandle);
}
//创建监听socket
Listen =
WSASocket(AF_INET,
SOCK_STREAM,
0,
NULL,
0,
WSA_FLAG_OVERLAPPED);
InternetAddr.sin_family =
PF_INET;
InternetAddr.sin_port =
htons(10000);
InternetAddr.sin_addr.s_addr =
htonl(INADDR_ANY);
//帮定到指定端口
bind(Listen,
(SOCKADDR*)&InternetAddr, sizeof(InternetAddr));
//开始监听
listen(Listen,
SOMAXCONN);
//完成端口帮定到监听socket
if
(CreateIoCompletionPort((HANDLE) Listen, CompletionPort,
(ULONG_PTR)&Listen, count) == NULL)
{
printf("CreateIoCompletionPort failed with error %d\n",
GetLastError());
return 1;
}
//创建事件
g_hAcceptExOverEvent =
CreateEvent(NULL, FALSE, FALSE, NULL);
if(!g_hAcceptExOverEvent)
{
return
1;
}
//帮定事件,由于我们用AcceptEx是一个异步的投递,这样帮定之后,如果投递的AcceptEx事件全部完成
//则g_hAcceptExOverEvent事件得到通知,进而同步AcceptEx调用
if(WSAEventSelect(Listen, g_hAcceptExOverEvent, FD_ACCEPT) ==
SOCKET_ERROR)
{
return
1;
}
//由于开始是复位,变成置位
SetEvent(g_hAcceptExOverEvent);
BOOL b =
TRUE;
while
(b)
{
//每次投递10次,进入等待状态,当AcceptEx全部完成之后,继续投递
if(WaitForSingleObject(g_hAcceptExOverEvent, INFINITE) ==
WAIT_FAILED)
continue;
for(int i
=0;i<10;i++)
{
int zero
=0;
PER_IO_DATA * pper_io_data =
NULL;
DWORD dwAddrLen =
sizeof(sockaddr_in)+16;
pper_io_data = (PER_IO_DATA
*)g_per_io_data.alloc_particle();
pper_io_data ->Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
NULL, 0,
WSA_FLAG_OVERLAPPED);
pper_io_data->OperationType =
OP_ACCEPT;
pper_io_data->lpSession=NULL;
ZeroMemory(&pper_io_data->Overlapped,sizeof(OVERLAPPED));//一定要注意清零
//这里pper_io_data->Overlapped,将来会在工作线程里返回,工作线程里有这样的代码
//bRet =
GetQueuedCompletionStatus(CompletionPort,
//
&BytesTransferred,
//
(PULONG_PTR)
//
&lpCompletionKey,
//
(LPOVERLAPPED*)
//
&pOldPerIoData,
//
INFINITE);
//我们这里为什么可以这么用pOldPerIoData,是因为它是一个PER_IO_DATA指针,但是PER_IO_DATA结构的第一成员是
//Overlapped,所以pper_io_data->Overlapped与pOldPerIoData地址是相同的。
if(!AcceptEx(Listen,pper_io_data ->Socket,pper_io_data
->buffer,0,dwAddrLen,dwAddrLen,&pper_io_data
->BufferLen,&pper_io_data->Overlapped))
{
if(WSAGetLastError() !=
ERROR_IO_PENDING)//对于AcceptEx,WSARecv,WSASend一定要有这样的判断,因为是异步的所以不会立即完成
{
closesocket(pper_io_data->Socket);
g_per_io_data.free_particle(pper_io_data);
//归还结构体到内存池
continue;
}
}
}
}
CloseHandle(g_hAcceptExOverEvent);
return
0;
}
DWORD WINAPI ServerWorkerThread(LPVOID
lpParam)
{
HANDLE
CompletionPort = (HANDLE)lpParam;
DWORD
BytesTransferred;
LPPER_IO_DATA pOldPerIoData
= NULL;
LPPER_IO_DATA pNewPerIoData =
NULL;
LPPER_HANDLE_DATA lpSession
=NULL;
LPVOID lpCompletionKey =
NULL;
DWORD
RecvBytes;
DWORD
Flags;
BOOL bRet = FALSE;
while
(1)
{
bRet =
GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(PULONG_PTR)
&lpCompletionKey,
(LPOVERLAPPED*)
&pOldPerIoData,
INFINITE);
if(!bRet
&&
!pOldPerIoData)//没有从完成队列中取到任何东西。
{
continue;
}
if(bRet ==
ERROR_SUCCESS
&&
BytesTransferred == 0 &&
pOldPerIoData)//断开连接
{
closesocket(pOldPerIoData->Socket);
//关闭socket
g_session.remove(lpSession);
//从Session链表中删除
g_per_handle_data.free_particle(lpSession);
//将Session归还到池
g_per_io_data.free_particle(pOldPerIoData);
}
switch
(pOldPerIoData->OperationType)
{
case
OP_ACCEPT://有连接进来
{
if(!bRet)//连接失败
{
closesocket(pOldPerIoData->Socket);
g_per_io_data.free_particle(pOldPerIoData);
break;
}
//用每个连接(客户端)相关的数据(g_per_handle_data)帮定完成键
lpSession=g_per_handle_data.alloc_particle();
lpSession->Socket =
pOldPerIoData->Socket;//就是我们AcceptEx时传入的socket
g_session.push_front(lpSession);
if(!CreateIoCompletionPort(
(HANDLE)pOldPerIoData->Socket,
CompletionPort,
(ULONG_PTR)lpSession,
count))
{
closesocket(pOldPerIoData->Socket);
//关闭socket
g_session.remove(lpSession);
//从Session链表中删除
g_per_handle_data.free_particle(lpSession);
//将Session归还到池
}
else
{
//向完成队列投递异步读操作
//分配操作缓存,g_per_io_data与每次读写相关联
pNewPerIoData =
(LPPER_IO_DATA)g_per_io_data.alloc_particle();
pNewPerIoData->Socket =
pOldPerIoData->Socket;
pNewPerIoData->OperationType =
OP_READ;
ZeroMemory(&(pNewPerIoData->Overlapped),
sizeof(OVERLAPPED));
Flags =
0;
pNewPerIoData->DataBuf.len =
1024;
pNewPerIoData->DataBuf.buf =
pNewPerIoData->buffer;
pNewPerIoData->lpSession =
g_per_handle_data.alloc_particle();
if(WSARecv(pNewPerIoData->Socket,
&(pNewPerIoData->DataBuf),
1,
&RecvBytes,
&Flags,
&(pNewPerIoData->Overlapped),
NULL)==
SOCKET_ERROR)
{
if(WSAGetLastError() !=
ERROR_IO_PENDING)//读操作失败
{
closesocket(pOldPerIoData->Socket);
//关闭socket
g_session.remove(pNewPerIoData->lpSession);
//从Session链表中删除
g_per_handle_data.free_particle(pNewPerIoData->lpSession);
//将Session归还到池
g_per_io_data.free_particle(pNewPerIoData);//归还OV结构体到内存池
}
}
}
g_per_io_data.free_particle(pOldPerIoData);
}
break;
case
OP_READ:
pNewPerIoData =
(LPPER_IO_DATA)g_per_io_data.alloc_particle();
if
(pNewPerIoData)
{
pNewPerIoData->Socket =
pOldPerIoData->Socket;
pNewPerIoData->OperationType =
OP_READ;
ZeroMemory(&(pNewPerIoData->Overlapped),
sizeof(OVERLAPPED));
Flags =
0;
pNewPerIoData->DataBuf.len =
1024;
pNewPerIoData->DataBuf.buf =
pNewPerIoData->buffer;
pNewPerIoData->OperationType = 0; //
read
pNewPerIoData->lpSession =
pOldPerIoData->lpSession;
if(WSARecv(pNewPerIoData->Socket,
&(pNewPerIoData->DataBuf),
1,
&RecvBytes,
&Flags,
&(pNewPerIoData->Overlapped),
NULL)==
SOCKET_ERROR)
{
if(WSAGetLastError() !=
ERROR_IO_PENDING)
{
closesocket(pOldPerIoData->Socket);
//关闭socket
g_session.remove(pNewPerIoData->lpSession);
//从Session链表中删除
g_per_handle_data.free_particle(pNewPerIoData->lpSession);
//将Session归还到池
g_per_io_data.free_particle(pNewPerIoData);//归还OV结构体到内存池
}
}
cout << pOldPerIoData->DataBuf.buf <<
endl;
send(pOldPerIoData->Socket,"9876543210",lstrlen("9876543210")+1,0);
g_per_io_data.free_particle(pOldPerIoData);
}
break;
case
OP_WRITE:
break;
default:
break;
}
}
}
分享到:
相关推荐
在Windows系统中,I/O Completion Ports (IOCP) 是一种高效能的异步I/O模型,常用于网络编程,特别是高并发服务器的实现。本文将深入探讨如何利用Visual C++和IOCP完成端口技术来构建一个网络数据传输的服务器和...
Windows IO Completion Ports (IOCP) 是一种高效率的异步I/O模型,它在Windows操作系统中用于处理大量的并发网络连接。这个"windows iocp网络通讯库封装"显然是一个使用IOCP实现的C++库,它可能包含了客户端和服务器...
本文将深入探讨如何构建一个高效率的UDP通信服务端,利用IOCP(I/O完成端口)技术来提升性能。IOCP是Windows操作系统提供的一种高级I/O模型,它可以有效地处理大量并发的I/O操作,特别适合于高负载、高性能的网络...
2. **绑定套接字到IOCP**:使用`CreateIoCompletionPort`函数将TCP或UDP套接字与IOCP关联,这样所有针对这些套接字的I/O操作完成后都会将通知发送到IOCP。 3. **接收客户端连接**:对于TCP,服务器会监听特定端口,...
"UDP+IOCP完成端口实现多播"是一个高级话题,涉及到网络通信中的用户数据报协议(UDP)、I/O完成端口(IOCP)以及多播技术。下面我们将详细探讨这些知识点。 1. **用户数据报协议(UDP)**: UDP是一种无连接的...
Windows Socket IOCP(I/O Completion Port)是一种高效率的异步I/O模型,它在Windows操作系统中被广泛用于网络编程,特别是在需要处理大量并发连接和数据传输的高性能服务器应用程序中。IOCP允许开发者以非阻塞的...
在Windows操作系统中,I/O完成端口(Input/Output Completion Port,简称IOCP)是一种高效、多线程的I/O模型,特别适用于处理大量并发网络请求。本资源包旨在深入探讨IOCP的工作原理以及如何在Windows环境下实现一个...
**IOCP(I/O完成端口)**是Windows操作系统中的一种高效、多线程I/O模型,主要用于处理大量并发的网络连接。IOCP利用操作系统的内核态完成数据传输,从而减少用户态与内核态之间的上下文切换,提高系统性能。在本...
{**************************************************** IOCP Socket Server 主要参考自CodeProject下载源码, 特别感谢张无忌的帮助 这个版本还很粗糙,很多地方没有处理好,最近 比较忙,没有精力和时间来完善它...
2. **IOCP管理类**:负责创建、销毁IOCP,以及将套接字与IOCP关联,处理IOCP的完成队列。 3. **线程池**:为IOCP提供工作线程,用于处理完成的I/O操作。 4. **网络协议处理**:实现TCP或UDP的协议解析和数据封装。 5...
在.NET编程环境中,C# IOCP(完成端口,I/O Completion Ports)是一种高级的并发I/O模型,常用于构建高性能的服务器应用。IOCP模型是Windows操作系统提供的一种高效的异步I/O机制,它能够充分利用多核处理器的优势,...
在这个"VC的IOCP开发,iocp类,demo"中,我们将深入探讨IOCP的基本原理、如何在VC++环境中实现一个基于IOCP的服务器,并通过提供的"IOCPDemo"来理解其实现细节。 一、IOCP基础知识 IOCP是Windows系统内核提供的一个...
IOCP(Input/Output Completion Port,输入/输出完成端口)是Windows操作系统提供的一种高度优化的I/O模型,尤其适用于高并发的网络编程场景。它允许应用程序通过一个或多个线程处理大量的I/O请求,提高了系统资源的...
Windows下IOCP模型 socket服务器端实例 1. 创建服务器socket, 并将socket设置为非阻塞模式 2. bind()绑定IP地此与端口 3. listen() 4. 创建IO完成端口,将socket绑定到IO完成端口上 5. 根据当前机器CPU个数创建工作...
"C++线程池结合IOCP完成端口实现socket高并发服务端程序"是一个利用现代C++特性,结合IO Completion Ports(IOCP)技术以及线程池策略来优化socket服务器性能的项目。IOCP是Windows操作系统中一种高效的I/O模型,...
IOCP(Input/Output Completion Port,输入/输出完成端口)是Windows操作系统提供的一种高度优化的多线程I/O模型,常用于构建高性能的游戏服务器、网络应用等。在这个"完整的IOCP实例"中,开发者使用了NT6线程池和...
本文将详细解析标题为“C# IOCP高性能 SOCKET并发完成端口例子(有C#客户端)完整实例源码”的技术知识点,以及如何利用C#进行IOCP(I/O完成端口)开发,实现广域网下的高效SOCKET通信。 首先,我们要理解什么是...
**IOCP.NET:深入理解与应用** IOCP.NET是一个针对C#.NET和VB.NET开发的高性能、高效率的异步I/O复用库,它基于Windows操作系统的完成端口(IO Completion Port,简称IOCP)机制。IOCP是Windows内核提供的一种优化...
IOCP,全称为I/O Completion Port,是Windows操作系统中一种高效处理并发I/O操作的机制。它是Windows系统为网络服务器和高性能应用程序设计的一种高级I/O模型,尤其适用于处理大量并发连接。本文将深入探讨IOCP的...