本文主要介绍一个c# AcceptEx和IOCP结合的例子,帮助你更好的理解和学习使用c#。感兴趣的朋友可以了解一下。
目录
前言:为什么需要用AcceptExIocpAcceptEx的外部函数解释实现步骤?附言
前言
Iocp(完成端口)是windows平台下实现高性能网络服务器的唯一选择。编写web服务器面临的问题有:
1快速接收客户端的连接。
2快速发送和接收数据。
3快速处理数据。本文主要解决第一个问题。
AcceptEx函数定义
布尔接受指数(
插座滑动插座,
套接字套接字,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
接收到LPDWORD lpdwBytesReceived,
LP重叠LP重叠
);
为什么要用AcceptEx
传统的接受功能可以满足大部分场景的需求;但是,在某些极端条件下,必须使用acceptEx来实现。这两种功能的区别如下:
1)接受受阻;在端口监视器中,必须启动一个专用线程来调用accept。当然你也可以用迂回的方式绕过这个限制,处理起来会很麻烦。请参阅单线程实现一文,以便同时监控多个端口。AcceptEx是异步的,可以同时处理许多端口监视器(监听端口的数量没有上限)。用迂回的方式,使用接受监听,一个线程最多可以监听64个端口。这可能不是AcceptEx最大的优势,毕竟同时有多个端口监听是非常罕见的。
2)AcceptEx可以返回更多的数据。A)AcceptEx可以返回本地和相反的ip地址和端口;不需要调用函数getsockname和getpeername来获取网络地址。b)在返回之前,AcceptEx可以接收另一段数据。这种做法有利有弊,一般不推荐。
3)AcceptEx就是在接收之前准备好插座。为了应对突如其来的连接高峰,可以多次启动AcceptEx。Accept是事后建立套接字,即tcp三次握手完成后,accept调用返回,然后生成套接字。套接字生成是一个比较耗时的操作,accept方法无法及时处理突发连接。建议对AcceptEx处理如下:一个线程负责创建socket,另一个线程负责处理AcceptEx的返回。
AcceptEx的特点只在文字上说明。通过下面的具体代码,逐一分析。我将AcceptEx的处理封装到IocpAcceptEx类中。写这个类的时候尽量做到高内聚低耦合,这样这个类就可以方便的被其他模块使用。
IocpAcceptEx外部功能说明
IocpAcceptEx类
{
公共:
iopacceptex();
~ iopacceptex();
//设置回调接口。当接受成功时,调用回调接口。
void set callback(iaceptcallback * callback);
//添加监听端口
void AddListenPort(UINT16端口);
//启动服务
BOOL Start();
void Stop();下面的代码被省略
}
#定义过帐_接受1
//若要使用IocpAcceptEx类,必须实现此接口。接收客户端的连接
IAcceptCallback类
{
公共:
virtual void on accept client(SOCKET hsocket client,uint 16 nListenPort)=0;
};
该类的调用功能简单,对外接口清晰。把这一类的责任交代清楚,也符合单一责任原则。
实现步骤说明
AcceptEx不仅需要绑定到侦听端口,还需要绑定到完成端口。所以程序的第一步是创建完成端口:
a)创建完成的端口。
m _ hio CP=CreateIoCompletionPort(INVALID _ HANDLE _ VALUE,NULL,NULL,0);
if (m_hIocp==NULL)
返回FALSE
b)监控端口创建和绑定
//生成套接字
SOCKET server SOCKET=WSA SOCKET(AF _ INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA _ FLAG _ OVERLAPPED);
if(server SOCKET==INVALID _ SOCKET)
{
返回false
}
//绑定
SOCKADDR _ IN addr
memset(addr,0,sizeof(addr));
addr.sin _ family=AF _ INET
addr . sin _ addr . s _ addr=in addr _ ANY;
addr . sin _ port=htons(port);
if (bind(serverSocket,(sockaddr *)addr,sizeof(addr))!=0)
{
close socket(server socket);
serverSocket=INVALID _套接字;
返回false
}
//开始监控
if (listen(serverSocket,SOMAXCONN)!=0)
{
关闭套接字(服务器套接字);
serverSocket=无效_套接字;
返回错误的
}
//监听端口与完成端口绑定
if(CreateIoCompletionPort((HANDLE)服务器套接字,m_hIocp,(ULONG_PTR)this,0)==NULL)
{
关闭套接字(服务器套接字);
serverSocket=无效_套接字;
返回错误的
}
c)投递AcceptEx
结构接受重叠
{
重叠重叠;
INT32 opType
套接字服务器套接字
(电源)插座客户端(电源)插座
char lpOutputBuf[128];
DWORD dwBytes
};
int iopacceptex:new accept(套接字服务器套接字)
{
//创建(电源)插座
SOCKET _socket=socket(AF_INET,SOCK_STREAM,IP proto _ TCP);
接受重叠* ov=new接受重叠();
ZeroMemory(ov,sizeof(接受重叠));
ov-opType=POST _ ACCEPT;
ov-client socket=_ socket;
ov-服务器套接字=服务器套接字;
//存放网络地址的长度
int addrLen=sizeof(sockaddr _ in)16;
int bret val=AcceptEx(服务器套接字,_socket,ov-lpOutputBuf,
0,地址,地址,
ov-dwBytes,(LP重叠)ov);
if (bRetVal==FALSE)
{
int error=WSAGetLastError();
如果(错误!=WSA_IO_PENDING)
{
关闭socket(_ socket);
返回0;
}
}
返回1;
}
AcceptEx是非阻塞操作,调用会立即返回。当有客户端连接时,怎么得到通知。答案是通过完成端口返回。注意有一个步骤:监听端口与完成端口绑定,就是服务器套接字与m_hIocp绑定,所以当有客户端连接服务器套接字时,m_hIocp会得到通知。需要生成线程,等待完成端口的通知。
d)通过完成端口,获取通知
DWORD dwBytesTransferred
ULONG_PTR键;
布尔rc
(同Internationalorganizations)国际组织错误;
接受overlapped * lpPerIOData=NULL
while (m_bServerStart)
{
错误=否_错误
rc=GetQueuedCompletionStatus(
m_hIocp,
dwBytesTransferred,
钥匙,
(LPOVERLAPPED *)lpPerIOData,
无限);
if (rc==FALSE)
{
误差=0;
if (lpPerIOData==NULL)
{
DWORD lastError=GetLastError();
if (lastError==WAIT_TIMEOUT)
{
继续;
}
其他
{
断言(假);
返回lastError
}
}
}
if (lpPerIOData!=空)
{
开关(lpPerIOData-opType)
{
案例发布_接受:
{
OnIocpAccept(lpPerIOData,dwBytesTransferred,error);
}
打破;
}
}
其他
{
}
}
返回0;
DWORD WINAPI IOP acceptex:AcceptExThreadPool(PV oid p context)
{
ThreadPoolParam * param=(ThreadPoolParam *)p上下文;
param-piocpaceptex-new accept(param-serve socket);
删除参数;
返回0;
}
int iopacceptex:OnIocpAccept(接受重叠*接受数据,int transLen,int error)
{
m _ iaceptcallback-on accept client(接受数据-客户端套接字,接受数据-服务器套接字);
//当一个AcceptEx返回,需要投递一个新的AcceptEx。
//使用线程池好像有点小题大做。前文已说过,套接字的创建相对是比较耗时的操作。
//如果不在线程池投递AcceptEx,AcceptEx的优点就被抹杀了。
ThreadPoolParam * param=new ThreadPoolParam();
param-piocpaceptex=this;
param-serve socket=接受数据服务器套接字;
QueueUserWorkItem(AcceptExThreadPool,this,0);
删除接受数据
返回0;
}
后记
采用完成端口是提高超正析象管(图片Orthicon)处理能力的一个途径(广义上讲,通讯操作也是IO)。为了提高超正析象管(图片Orthicon)处理能力,windows提供很多异步操作函数,这些函数都与完成端口关联,所以这一类处理的思路基本一致。学会了AcceptEx的使用,可以做到触类旁通的效果。
以上就是c# AcceptEx与完成端口(IOCP)结合的示例的详细内容,更多关于c# AcceptEx与完成端口(IOCP)结合的资料请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。