完成端口模型

完成端口模型步骤如下:

1.调用CreateIoCompletionPort函数创建完成端口。

HANDLE CompletionPort=CreateIoCompletionStatus(INVALID_HANDLE_VALUE,NULL,0,0);

2.创建和处理器数目相等的工作线程

SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
for(int i=0;i<SysInfo.)
for(int i=0;i<(sysInfo.dwNumberOfProcessors);i++)
{                                                                                                                                      HANDLE ThreadHandle=(HANDLE)_beginthreadex(NULL,0,CompletionPortProcessor,ComplPort,0,NULL);                                    CloseHandle(ThreadHandle);
}

3.接受客服端连接请求,创建单句柄数据,调用CreateIoCompletionPort将客服端套接字绑定到完成端口上。

单据句柄数据结构可以自己定义字段:

struct PTR_HANDLE_DATA
{//字段可以随意定义
      SOCKET s;
      int i;
}

将套接字绑定到完成端口上:

CreateIoCompletionPort(sClient,CompletionPort,(DWORD)PerHandleData,0);

4.创建单I/O数据,并将单I/O数据作为参数传递给重叠I/O函数:WSARecv、WSASend.

创建单I/O数据,该字段除了第一个字段必须为重叠结构OVERLAPPED外,其他字段可以自己定义:

<pre class="cpp" name="code">struct PER_IO_DATA
{
	OVERLAPPED Overlapped;
	WSABUF DataBuf;
	char Buffer[DATA_BUFFER];
	int OperationType;
};

调用重叠I/O函数:

WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);

5.在工作线程中,调用GetQueuedCompletionStatus函数等待完成端口的完成请求。

GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE))

6.等待成功后,对请求处理。如果需要再次投递一个重叠I/O。

一个简单的例子如下

#include <WinSock2.h>
#include <stdio.h>
#include <string.h>
#include <ws2tcpip.h>
#include <process.h>
#pragma     comment(lib, "ws2_32.lib ")  //linking to the library
#define DATA_BUFFER 4*1024
#define RECV_OPERATION	1
#define SEND_OPERATION  2

struct PTR_HANDLE_DATA
{
	SOCKET socket;
	int Location;
};
struct PER_IO_DATA
{
	OVERLAPPED Overlapped;
	WSABUF DataBuf;
	char Buffer[DATA_BUFFER];
	int OperationType;
};
unsigned int WINAPI CompletionPortProcessor(PVOID lParam)
{
    HANDLE CompletionPort = (HANDLE)lParam;
    DWORD BytesTransferred;
    PTR_HANDLE_DATA *PerHandleData;
    PER_IO_DATA *PerIoData;

    while(true)
    {

        if(0 == GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE))
        {
            if( (GetLastError() == WAIT_TIMEOUT) || (GetLastError() == ERROR_NETNAME_DELETED) )
            {
				closesocket(PerHandleData->socket);

                delete PerIoData;
                delete PerHandleData;
                continue;
            }
            return 0;
        }

        // 说明客户端已经退出
        if(BytesTransferred == 0)
        {
            closesocket(PerHandleData->socket);
            delete PerIoData;
            delete PerHandleData;
            continue;
        }
		if(PerIoData->OperationType==RECV_OPERATION)
		{
			printf("%d:%s\n",PerHandleData->Location,PerIoData->DataBuf.buf);
			// 继续向 socket 投递WSARecv操作
			DWORD Flags = 0;
			DWORD dwRecv = 0;
			ZeroMemory(PerIoData, sizeof(PER_IO_DATA));
			PerIoData->DataBuf.buf = PerIoData->Buffer;
			PerIoData->DataBuf.len = DATA_BUFFER;
			PerIoData->OperationType=RECV_OPERATION;
			WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);
		}
    }

    return 0;
}

void main()
{
	HANDLE ComplPort;
	ComplPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

	SYSTEM_INFO sysInfo;
	memset(&sysInfo,0,sizeof(sysInfo));
	GetSystemInfo(&sysInfo);
	HANDLE *handleArray=(HANDLE *)malloc(sysInfo.dwNumberOfProcessors *sizeof(HANDLE));
	for(int i=0;i<(sysInfo.dwNumberOfProcessors);i++)
	{
		handleArray[i]=(HANDLE)_beginthreadex(NULL,0,CompletionPortProcessor,ComplPort,0,NULL);
	}
	WSADATA  wsaData;
	WSAStartup(MAKEWORD(2,2),&wsaData);

	SOCKET s,sClient;
	struct addrinfo hints,*result;
	int rc;
	memset(&hints,0,sizeof(hints));
	hints.ai_flags=AI_NUMERICHOST;//nodename is ip address;if set AI_PASSIVE ,it is computer name;if set AI_CANONNAME ,it is ..
	hints.ai_family=AF_UNSPEC;//IPv4 OR IPv6;if IPv4,Set AF_INET; if IPv6,Set AF_INET6
	hints.ai_socktype=SOCK_STREAM;//SOCK_DRGAM
	hints.ai_protocol=IPPROTO_TCP;
	rc=getaddrinfo("127.0.0.1","5001",&hints,&result);
	s=socket(result->ai_family,result->ai_socktype,result->ai_protocol);
	bind(s,result->ai_addr,result->ai_addrlen);
	listen(s,5);
	PER_IO_DATA *PerIoData;
	PTR_HANDLE_DATA *PerHandleData;
	int i=1;
    while(true)
    {
        sClient = accept(s, 0,0);
        PerHandleData = new PTR_HANDLE_DATA();
		PerHandleData->socket = sClient;
		PerHandleData->Location=i;
        CreateIoCompletionPort((HANDLE)PerHandleData->socket, ComplPort, (DWORD)PerHandleData, 0);

        PerIoData = new PER_IO_DATA();
        ZeroMemory(PerIoData, sizeof(PER_IO_DATA));
        PerIoData->DataBuf.buf = PerIoData->Buffer;
        PerIoData->DataBuf.len =DATA_BUFFER;
		PerIoData->OperationType=RECV_OPERATION;

        DWORD Flags = 0;
        DWORD dwRecv = 0;
        WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);
		i++;
    }

    DWORD dwByteTrans;
    PostQueuedCompletionStatus(ComplPort, dwByteTrans, 0, 0);
    closesocket(s);
}
时间: 2024-11-08 23:47:32

完成端口模型的相关文章

Winsock完成端口模型-Delphi代码

原文出处 <Windows网络编程技术>第8章 完成端口模型 由于原书附的是C代码,我把其翻译成Delphi代码. 其中winsock2.pas在delphi中不带,要另外下载http://jungla.dit.upm.es/~bti/files/winsock2.pas program CompletionIO; {$APPTYPE CONSOLE} uses  SysUtils,  WinSock2 in 'WinSock2.pas',  Mains in 'Mains.pas'; beg

Socket编程模型之完成端口模型

转载请注明来源:http://blog.csdn.net/caoshiying?viewmode=contents 一.回顾重叠IO模型 用完成例程来实现重叠I/O比用事件通知简单得多.在这个模型中,主线程只用不停的接受连接即可:辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用.如果辅助线程不调用SleepEx,则内核在完成

C# IOCP完成端口模型(简单实用高效)

1.在C#中,不用去面对完成端口的操作系统内核对象,Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用.请参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1. 2.我的SocketAsyncEventArgsPool类使用List对象来存储对

套接字I/O模型-完成端口IOCP

“完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和Windows 2000操作系统.因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型.要记住的一个基本准则是,假如要为Windows NT或Windows 2000开发高性能的

Windows Socket五种I/O模型——代码全攻略(转)

Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权.这种模式使用 起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误.但功能强大.为了解决这个问题,提出了进行I/O操作的一些I/O模型,下面介绍最常见的三种: Windows Socket五种I/O模型——代码全攻

完成端口(Completion Port)详解(转)

手把手叫你玩转网络编程系列之三    完成端口(Completion Port)详解                                                              ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中……酝酿了两年之后,终于决定开始动笔了,但愿还不算晚….. 这篇文档我非常详细并且图文并茂的介绍了关于网络编程模型中完成端口的方方

IOCP模型总结(总结回顾)

IOCP旧代码重提,最近一直在玩其他方面的东东,时不时回顾一下,收益多多. IOCP(I/O Completion Port,I/O完成端口)是性能最好的一种I/O模型.它是应用程序使用线程池处理异步I/O请求的一种机制.在处理多个并发的异步I/O请求时,以往的模型都是在接收请求是创建一个线程来应答请求.这样就有很多的线程并行地运行在系统中.而这些线程都是可运行的,Windows内核花费大量的时间在进行线程的上下文切换,并没有多少时间花在线程运行上.再加上创建新线程的开销比较大,所以造成了效率的

完成端口(CompletionPort)详解

手把手叫你玩转网络编程系列之三    完成端口(Completion Port)详解                                                              ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中--酝酿了两年之后,终于决定开始动笔了,但愿还不算晚-.. 这篇文档我非常详细并且图文并茂的介绍了关于网络编程模型中完成端口的方方

完成端口与高性能服务器程序开发

原文出处:http://blog.csdn.NET/roen/archive/2007/03/19/1533378.aspx 以一个文件传输服务端为例,在我的机器上它只起两个线程就可以为很多个客户端同时提供文件下载服务,程序的性能会随机器内CPU个数的增加而线性增长,我 尽可能做到使它清晰易懂,虽然程序很小却用到了NT 5的一些新特性,重叠IO,完成端口以及线程池,基于这种模型的服务端程序应该是NT系统上性能最好的了. 首先.做为完成端口的基础,我们应该理解重叠IO,这需要你已经理解了内核对象及