,,c# AcceptEx与完成端口(IOCP)结合的示例

,,c# AcceptEx与完成端口(IOCP)结合的示例

本文主要介绍一个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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • 设计一个简单的C#控制台应用程序,C#控制台程序,C# 创建控制台应用程序
  • 深入解析windows第8版,深入解析C#(第4版)
  • 数组代码,c# 数组操作,C# 数组实例介绍(图文)
  • 学会C#要多久,学会c#要多久,c#学习之30分钟学会XAML
  • 回溯法01背包问题c,回溯法求解01背包问题伪代码,C#使用回溯法解决背包问题实例分析
  • xml文件转义字符,xml转意字符,C# XML中的转义字符操作
  • winform 进度条控件,c# 进度条使用
  • winform 进度条控件,c# 进度条使用,C#使用winform实现进度条效果
  • winform backgroundworker,c# isbackground
  • winform backgroundworker,c# isbackground,C# BackgroundWorker用法详解
  • lua与c#交互,lua c#
  • lua与c#交互,lua c#,ToLua框架下C#与Lua代码的互调操作
  • linq c#,linq原理 c#
  • linq c#,linq原理 c#,c#中LINQ的基本用法实例
  • java decimal保留两位小数,sql中decimal函数保留2位小数,C#中decimal保留2位有效小数的实现方法
  • 留言与评论(共有 条评论)
       
    验证码: