WINDOWS下的异步非阻塞的模型:
线程池完成高并发,共享内存完成非阻塞

ctcpnet.h
#ifndef CTCPNET_H
#define CTCPNET_H
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <list>
#include <map>
#include <iostream>
#include <QDebug>
#include <mswsock.h>
using namespace std;
#define MAXNUM 64
#define MAXCONTENT 4096
enum NetType{NT_ACCEPT,NT_READ};
//LPOVERLAPPED返回结构体首地址,所以定义结构体时一定要先声明OVERLAPPED m_olp
struct Mysocket
{
OVERLAPPED m_olp;//事件 必须要这么写 定义结构体成员顺序要注意
SOCKET m_sock; //waiter
char m_szbuf[MAXCONTENT]; //缓冲区
NetType m_nType;//网络事件
};
class CTCPNet
{
public:
CTCPNet();
public:
//初始化网络
bool InitNetWork();
void UnInitNetWork();
//收发数据
bool SendData(SOCKET sock,char *szbuf,int nlen);
void RecvData();
bool PostAccept();
public:
static unsigned _stdcall ThreadProc(void*);//全局变成局部
static unsigned _stdcall ThreadRecv(void*);
private:
SOCKET m_sock;
HANDLE m_thread;
bool m_flagquit;
list<HANDLE> m_lstThread;//用来存放创建线程返回的句柄
map<unsigned int,SOCKET> m_mapIdToSock;
HANDLE m_hIOCP;
list<Mysocket*> m_lstMysocket;
public:
HANDLE m_aryhEvent[MAXNUM];
SOCKET m_arySocket[MAXNUM];
int m_nEventNum;
};
#endif // CTCPNET_H
ctcpnet.cpp
#include "ctcpnet.h"
#include <winsock2.h>
#include <windows.h> //winsock.h
#include <iostream>
#include <QDebug>
using namespace std;
CTCPNet::CTCPNet()
{
m_sock = NULL;
m_flagquit = true;
m_nEventNum = 0;
ZeroMemory(m_aryhEvent,sizeof(m_aryhEvent));
ZeroMemory(m_arySocket,sizeof(m_arySocket));
}
bool CTCPNet::InitNetWork()
{
//1.选择种类 火锅 韩餐 烤肉--
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
printf("WSAStartup failed with error: %d\n", err);
return false;
}
if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2)
{
UnInitNetWork();
return false;
}
else
printf("The Winsock 2.2 dll was found okay\n");
//2.雇个店长--
m_sock = socket(AF_INET,SOCK_STREAM,0);
if(m_sock == INVALID_SOCKET)
{
UnInitNetWork();
return false;
}
//3.找个地方
sockaddr_in addrserver;
addrserver.sin_family = AF_INET;
addrserver.sin_port = htons(8899);
addrserver.sin_addr.S_un.S_addr = 0;
if(SOCKET_ERROR == bind(m_sock,( const sockaddr *)&addrserver,sizeof(addrserver)))
{
UnInitNetWork();
return false;
}
//4.店长宣传
if(SOCKET_ERROR == listen(m_sock,10))
{
UnInitNetWork();
return false;
}
//1.创建IOCP
m_hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,NULL);
if (m_hIOCP == NULL){
UnInitNetWork();
return false;
}
//2.将socketlisten交给完成端口管理
CreateIoCompletionPort((HANDLE)m_sock,//交给完成端口管理的套接字
m_hIOCP,//完成端口句柄
(ULONG_PTR)m_sock,//完成键
0);//线程的个数 默认和系统处理器一样的个数
//3.创建一堆waiter,交给socklisten 准备好了
//获取cpu*2
SYSTEM_INFO si; //SYSTEM_INFO结构体包含了当前计算机的信息。这个信息包括计算机的体系结构、中央处理器的类型、系统中中央处理器的数量、页面的大小以及其他信息。
GetSystemInfo(&si);
for(unsigned long i = 0; i<si.dwNumberOfProcessors*2;i++)//dwNumberOfProcessors:指定系统中的处理器的数目
{
PostAccept();
}
//4.创建线程池
for(unsigned long i = 0; i<si.dwNumberOfProcessors*2;i++){
m_thread = (HANDLE)_beginthreadex(0,0,&ThreadProc,this,0,0);
if(m_thread)
m_lstThread.push_back(m_thread);
}
return true;
}
bool CTCPNet::PostAccept()
{
//声明结构体对象
Mysocket *pSocket = new Mysocket;
//赋值
pSocket->m_nType = NT_ACCEPT;
pSocket->m_olp.hEvent = WSACreateEvent();
pSocket->m_sock = socket(AF_INET,SOCK_STREAM,0);
ZeroMemory(pSocket->m_szbuf,sizeof(pSocket->m_szbuf));
DWORD dwBytesReceived;
//投递接收连接请求
if(!AcceptEx(m_sock,//监听socket
pSocket->m_sock,//waiter
pSocket->m_szbuf,//缓冲区
0,//连接成功,立即返回
sizeof (sockaddr)+16,//本地地址长度
sizeof (sockaddr)+16,//远程地址长度
&dwBytesReceived,//接收传输字节数
&pSocket->m_olp//事件
))
{
if (WSAGetLastError() != ERROR_IO_PENDING)//还没有处理完的情况不算是错误
{
closesocket(pSocket->m_sock);
WSACloseEvent(pSocket->m_olp.hEvent);
delete pSocket;
pSocket = NULL;
return false;
}
}
m_lstMysocket.push_back(pSocket);
return true;
}
bool CTCPNet::PostRecv(Mysocket* pSocket)
{
pSocket->m_nType = NT_READ;
WSABUF wb;
wb.buf = pSocket->m_szbuf;
wb.len = sizeof (pSocket->m_szbuf);
DWORD dwNumberOfBytesRecvd;
DWORD dwFlags = FALSE;
if(WSARecv(pSocket->m_sock,//一个标识已连接套接口的描述字
&wb,//一个指向WSABUF结构数组的指针。每一个WSABUF结构包含一个缓冲区的指针和缓冲区的长度
1,//lpBuffers数组中WSABUF结构的数目。
&dwNumberOfBytesRecvd,//如果接收操作立即结束,一个指向本调用所接收的字节数的指针
&dwFlags,//一个指向标志位的指针
&pSocket->m_olp,//一个指向WSAOVERLAPPED结构的指针
NULL//一个指向接收操作结束后调用的例程的指针,在异步操作中可设置为NULL
))
{
if(WSAGetLastError() == WSA_IO_PENDING){
return false;
}
}
return true;
}
unsigned _stdcall CTCPNet::ThreadProc(void *lpvoid)
{
CTCPNet *pthis =(CTCPNet*)lpvoid;
//接收连接
DWORD dwNumberOfBytesTransferred;
SOCKET sock;
Mysocket *pSocket;
BOOL bFlag;//大BOOL类型 为int
while(pthis->m_flagquit)
{
//观察IOCP状态
bFlag=GetQueuedCompletionStatus(pthis->m_hIOCP,//观察哪一个完成端口
&dwNumberOfBytesTransferred,//接收的字节数
(PULONG_PTR)&sock,//完成键
(LPOVERLAPPED *)&pSocket,//OVERLAPPED是包含事件的结构体 LPOVERLAPPED:指向结构体得指针 LPOVERLAPPED *:二级指针 当前跟客户端连接的指针
INFINITE//等的时间
);
if(!bFlag){
//psocket 包含的就是下线的客户端对应的waiter
auto ite = pthis->m_lstMysocket.begin();
while (ite != pthis->m_lstMysocket.end())
{
if ((*ite)==pSocket)
{
WSACloseEvent((*ite)->m_olp.hEvent);
closesocket((*ite)->m_sock);
delete *ite;
*ite = NULL;
pthis->m_lstMysocket.erase(ite);
break;
}
ite++;
}
continue;
}
//校验参数
if (!sock || !pSocket)
continue;
switch(pSocket->m_nType){
case NT_ACCEPT:
//说明已经连接上了
//1.投递新的空闲waiter
pthis->PostAccept();
//2.投递接收数据请求
pthis->PostRecv(pSocket);
//3.将socket交给IOCP管理
CreateIoCompletionPort((HANDLE)pSocket->m_sock,//交给完成端口管理的套接字
pthis->m_hIOCP,//完成端口句柄
(ULONG_PTR)pSocket->m_sock,//完成键
0);//线程的个数 默认和系统处理器一样的个数
break;
case NT_READ:
//数据接收到了
pSocket->m_szbuf;
//处理数据
pthis->PostRecv(pSocket);
break;
default:
break;
}
}
return 0;
}
unsigned _stdcall CTCPNet::ThreadRecv(void *lpvoid)
{
//一个线程对应一个waiter 用map
CTCPNet *pthis =(CTCPNet*)lpvoid;
pthis->RecvData();
return 0;
}
void CTCPNet::RecvData()
{
//获取线程id映射sockWaiter
SOCKET sockWaiter = m_mapIdToSock[GetCurrentThreadId()];
int nPackSize;
int nRecvNum;
char* szbuf=NULL;
int offset;
while(m_flagquit)
{
nRecvNum = recv(sockWaiter,(char*)&nPackSize,sizeof (int),0);
if (nRecvNum<0)
{
//客户端下线
if (WSAGetLastError() == WSAECONNRESET)
{
break;
}
continue;
}
if (nPackSize<=0) continue;
//解决粘包问题
szbuf = new char[nPackSize];
offset = 0;
while(nPackSize)
{
nRecvNum = recv(sockWaiter,szbuf+offset,nPackSize,0);
offset += nRecvNum;
nPackSize -= nRecvNum;
}
//处理数据
cout<<szbuf<<endl;
delete []szbuf;
szbuf = NULL;
}
}
bool CTCPNet::SendData(SOCKET sock,char *szbuf,int nlen)
{
if(sock == INVALID_SOCKET || !szbuf || nlen<0)
return false;
//发送大小
if(send(sock,(char*)&nlen,sizeof(int),0) <= 0)
return false;
//发送内容
if(send(sock,szbuf,nlen,0)<=0)
return false;
return true;
}
void CTCPNet::UnInitNetWork()
{
//销毁线程
m_flagquit = false;
list<HANDLE>::iterator ite = m_lstThread.begin();
while(ite != m_lstThread.end()){
if (*ite)
{
if (WAIT_TIMEOUT==WaitForSingleObject(*ite,100))
{
TerminateThread(*ite,-1);
}
CloseHandle(*ite);
*ite = NULL;
}
ite++;
}
m_lstThread.clear();
//m_lstMysocket链表删除
auto itesocket = m_lstMysocket.begin();
while (itesocket != m_lstMysocket.end())
{
closesocket((*itesocket)->m_sock);
WSACloseEvent((*itesocket)->m_olp.hEvent);
delete *itesocket;
*itesocket = NULL;
itesocket++;
}
m_lstMysocket.clear();
//关闭套接字
if(m_sock){
closesocket(m_sock);
m_sock = NULL;
}
WSACleanup();
}
462

被折叠的 条评论
为什么被折叠?



