18,356
社区成员
发帖
与我相关
我的任务
分享
#pragma once
// winsock 2 的头文件和库
#include <winsock2.h>
#include <MSWSock.h>
#pragma comment(lib,"ws2_32.lib")
#include "afxtempl.h"
// 缓冲区长度 (1024*8)
// 之所以为什么设置8K,也是一个江湖上的经验值
// 如果确实客户端发来的每组数据都比较少,那么就设置得小一些,省内存
#define MAX_BUFFER_LEN 8192
// 默认端口
#define DEFAULT_PORT 5000
// 默认IP地址
#define DEFAULT_IP _T("127.0.0.1")
// 每一个处理器上产生多少个线程(为了最大限度的提升服务器性能,详见配套文档)
#define WORKER_THREADS_PER_PROCESSOR 2
//////////////////////////////////////////////////////////////////
// 在完成端口上投递的I/O操作的类型
typedef enum _OPERATION_TYPE
{
ACCEPT_POSTED, // 标志投递的Accept操作
SEND_POSTED, // 标志投递的是发送操作
RECV_POSTED, // 标志投递的是接收操作
NULL_POSTED // 用于初始化,无意义
}OPERATION_TYPE;
//====================================================================================
//
// 单IO数据结构体定义(用于每一个重叠操作的参数)
//
//====================================================================================
typedef struct _PER_IO_CONTEXT
{
OVERLAPPED m_Overlapped; // 每一个重叠网络操作的重叠结构(针对每一个Socket的每一个操作,都要有一个)
SOCKET m_sockAccept; // 这个网络操作所使用的Socket
WSABUF m_wsaBuf; // WSA类型的缓冲区,用于给重叠操作传参数的
char m_szBuffer[MAX_BUFFER_LEN]; // 这个是WSABUF里具体存字符的缓冲区
OPERATION_TYPE m_OpType; // 标识网络操作的类型(对应上面的枚举)
// 初始化
_PER_IO_CONTEXT()
{
ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
ZeroMemory( m_szBuffer,MAX_BUFFER_LEN );
m_sockAccept = INVALID_SOCKET;
m_wsaBuf.buf = m_szBuffer;
m_wsaBuf.len = MAX_BUFFER_LEN;
m_OpType = NULL_POSTED;
}
// 释放掉Socket
~_PER_IO_CONTEXT()
{
if( m_sockAccept!=INVALID_SOCKET )
{
closesocket(m_sockAccept);
m_sockAccept = INVALID_SOCKET;
}
}
// 重置缓冲区内容
void ResetBuffer()
{
ZeroMemory( m_szBuffer,MAX_BUFFER_LEN );
}
} PER_IO_CONTEXT, *PPER_IO_CONTEXT;
//====================================================================================
//
// 单句柄数据结构体定义(用于每一个完成端口,也就是每一个Socket的参数)
//
//====================================================================================
typedef struct _PER_SOCKET_CONTEXT
{
SOCKET m_Socket; // 每一个客户端连接的Socket
SOCKADDR_IN m_ClientAddr; // 客户端的地址
CArray< _PER_IO_CONTEXT * > m_arrayIoContext; // 客户端网络操作的上下文数据,也就是说对于每一个客户端Socket,是可以在上面同时投递多个IO请求的
// 初始化
_PER_SOCKET_CONTEXT()
{
m_Socket = INVALID_SOCKET;
memset(&m_ClientAddr, 0, sizeof(m_ClientAddr));
}
// 释放资源
~_PER_SOCKET_CONTEXT()
{
if( m_Socket!=INVALID_SOCKET )
{
closesocket( m_Socket );
m_Socket = INVALID_SOCKET;
}
// 释放掉所有的IO上下文数据
for( int i=0;i<m_arrayIoContext.GetCount();i++ )
{
delete m_arrayIoContext.GetAt(i);
}
m_arrayIoContext.RemoveAll();
}
// 获取一个新的IoContext
_PER_IO_CONTEXT* GetNewIoContext()
{
_PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
m_arrayIoContext.Add( p );
return p;
}
// 从数组中移除一个指定的IoContext
void RemoveContext( _PER_IO_CONTEXT* pContext )
{
ASSERT( pContext!=NULL );
for( int i=0;i<m_arrayIoContext.GetCount();i++ )
{
if( pContext==m_arrayIoContext.GetAt(i) )
{
delete pContext;
pContext = NULL;
m_arrayIoContext.RemoveAt(i);
break;
}
}
}
} PER_SOCKET_CONTEXT, *PPER_SOCKET_CONTEXT;