您的位置:首页 > 其它

见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点

2011-08-25 15:20 459 查看
要分析的实例分为两个线程:

分别是主线程(MAIN),还有一个是创建的线程(ServerThread)

1.主函数完成初始化工作:

1.1: (主线程)HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 创建完成端口对象

1.2: (主线程)::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0); 创建线程用于接收等

1.3:(主线程)调用socket(),SOCKADDR_IN,bind(),listen(),初始化套接字

1.4: (线程函数)HANDLE hCompletion = (HANDLE)lpParam; 通过线程参数得到完成端口对象

1.5: (线程函数) while(TRUE) 定义循环 循环等待套接字上发生事件

1.6:(线程函数) ::GetQueuedCompletionStatus() 在关联到此完成端口的所有套节字上等待I/O完成

1.7: (主线程) SOCKADDR_IN saRemote; SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen); 为新连接建立结构并等待连接请求

2.有连接发生:

2.1: (主线程while循环中) PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));

创建PPER_HANDLE_DATA结构

2.2: (主线程while循环中) ::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);

完成 完成端口 与 套接字关联

2.3: (主线程while循环中) 给pPerIO结构 添加类型

PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));

pPerIO->nOperationType = OP_READ;

WSABUF buf;

buf.buf = pPerIO->buf;

buf.len = BUFFER_SIZE;

DWORD dwRecv;

DWORD dwFlags = 0;

2.4: (主线程while循环中) ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL); 发送异步接收请求

2.5: (主线程while循环中) 回到WHILE循环accept()函数处 等待新连接

2.6: (线程函数while循环中)GetQueuedCompletionStatus() 此时I/O完成 开始处理消息

2.7: (线程函数while循环中)pPerIO->nOperationType 通过类型判断 消息类型

2.7:(线程函数while循环中)打印接收的消息 并在此投递 一个完成端口

pPerIO->buf[dwTrans] = '\0';

printf(pPerIO -> buf);

WSABUF buf;

buf.buf = pPerIO->buf ;

buf.len = BUFFER_SIZE;

pPerIO->nOperationType = OP_READ;

DWORD nFlags = 0;

printf("12\n");

::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);

2.8:(线程函数while循环中) 由于又有端口I/O完成 ::GetQueuedCompletionStatus()函数 继续判断并处理

2.9:(线程函数while循环中) 由于没有数据 GetQueuedCompletionStatus()返回值为错误 调用一下函数关闭

::closesocket(pPerHandle->s);

::GlobalFree(pPerHandle);

::GlobalFree(pPerIO);

2.10:(线程函数while循环中) 在此回到while循环 调用::GetQueuedCompletionStatus()函数 继续等待

// iocpTP.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <stdio.h>

#include <windows.h>

// 初始化Winsock库

#include <winsock2.h>

#pragma comment(lib,"WS2_32.lib") //

#define BUFFER_SIZE 1024

typedef struct _PER_HANDLE_DATA // per-handle数据

{

SOCKET s;
// 对应的套节字句柄

sockaddr_in addr;// 客户方地址

} PER_HANDLE_DATA, *PPER_HANDLE_DATA;

typedef struct _PER_IO_DATA // per-I/O数据

{

OVERLAPPED ol;// 重叠结构

char buf[BUFFER_SIZE];// 数据缓冲区

int nOperationType;// 操作类型

#define OP_READ 1

#define OP_WRITE 2

#define OP_ACCEPT 3

} PER_IO_DATA, *PPER_IO_DATA;

DWORD WINAPI ServerThread(LPVOID lpParam)

{

// 得到完成端口对象句柄

HANDLE hCompletion = (HANDLE)lpParam;

printf("ServerThread Processor\n");

DWORD dwTrans;

PPER_HANDLE_DATA pPerHandle;

PPER_IO_DATA pPerIO;

while(TRUE)

{

// 在关联到此完成端口的所有套节字上等待I/O完成

printf("wait GetQueuedCompletionStatus Done \n");

BOOL bOK = ::GetQueuedCompletionStatus(hCompletion,

&dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);

if(!bOK)
// 在此套节字上有错误发生

{

printf("9\n");

::closesocket(pPerHandle->s);

::GlobalFree(pPerHandle);

::GlobalFree(pPerIO);

continue;

}

if(dwTrans == 0 &&// 套节字被对方关闭

(pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))

{

printf("10\n");

::closesocket(pPerHandle->s);

::GlobalFree(pPerHandle);

::GlobalFree(pPerIO);

continue;

}

printf("11\n");

switch(pPerIO->nOperationType)// 通过per-I/O数据中的nOperationType域查看什么I/O请求完成了

{

case OP_READ:
// 完成一个接收请求

{

pPerIO->buf[dwTrans] = '\0';

printf(pPerIO -> buf);

// 继续投递接收I/O请求

WSABUF buf;

buf.buf = pPerIO->buf ;

buf.len = BUFFER_SIZE;

pPerIO->nOperationType = OP_READ;

DWORD nFlags = 0;

printf("12\n");

::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);

}

break;

case OP_WRITE: // 本例中没有投递这些类型的I/O请求

{

WSABUF buf;

buf.buf = pPerIO->buf ;

buf.len = BUFFER_SIZE;

pPerIO->nOperationType = OP_READ;

DWORD nFlags = 0;

::WSASend(pPerHandle->s, &buf, 1, &dwTrans, nFlags, &pPerIO->ol, NULL);

}

break;

case OP_ACCEPT:

{

}

break;

}

}

return 0;

}

void main()

{

// 初始化WS2_32.dll

BYTE minorVer = 0x02;

BYTE majorVer = 0x02;

WSADATA wsaData;

WORD sockVersion = MAKEWORD(minorVer, majorVer);

if(::WSAStartup(sockVersion, &wsaData) != 0)

{

}

int nPort = 5000;

// 创建完成端口对象,创建工作线程处理完成端口对象中事件

printf("Init NetWork\n");

HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);

printf("CreateIoCompletionPort Done\n");

::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);

printf("Create Server Thread \n");

// 创建监听套节字,绑定到本地地址,开始监听

SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, 0);

SOCKADDR_IN si;

si.sin_family = AF_INET;

si.sin_port = ::ntohs(nPort);

si.sin_addr.S_un.S_addr = INADDR_ANY;

::bind(sListen, (sockaddr*)&si, sizeof(si));

::listen(sListen, 5);

printf("Start Listen \n");

// 循环处理到来的连接

while(TRUE)

{

// 等待接受未决的连接请求

printf("Wait for Connect...\n");

SOCKADDR_IN saRemote;

int nRemoteLen = sizeof(saRemote);

SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen);

// 接受到新连接之后,为它创建一个per-handle数据,并将它们关联到完成端口对象。

PPER_HANDLE_DATA pPerHandle =

(PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));

pPerHandle->s = sNew;

memcpy(&pPerHandle->addr, &saRemote, nRemoteLen);

::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);

printf("Accept connect , assigned a CreateIoCompletionPort \n");

// 投递一个接收请求

PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));

pPerIO->nOperationType = OP_READ;

WSABUF buf;

buf.buf = pPerIO->buf;

buf.len = BUFFER_SIZE;

DWORD dwRecv;

DWORD dwFlags = 0;

printf(" Mail a request!!! \n");

::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);

}

::WSACleanup();

}

测试程序:

//////////////////////////////////////////////////////////

// TCPClient.cppÎļþ

#include <stdio.h>

#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main()

{

BYTE minorVer = 0x02;

BYTE majorVer = 0x02;

//WS2_32.dll

WSADATA wsaData;

WORD sockVersion = MAKEWORD(minorVer, majorVer);

if(::WSAStartup(sockVersion, &wsaData) != 0)

{

exit(0);

}

// ´´½¨Ì×½Ú×Ö

SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if(s == INVALID_SOCKET)

{

printf(" Failed socket() \n");

return 0;

}

// Ò²¿ÉÒÔÔÚÕâÀïµ÷ÓÃbindº¯Êý°ó¶¨Ò»¸ö±¾µØµØÖ·

// ·ñÔòϵͳ½«»á×Ô¶¯°²ÅÅ

// ÌîдԶ³ÌµØÖ·ÐÅÏ¢

sockaddr_in servAddr;

servAddr.sin_family = AF_INET;

servAddr.sin_port = htons(5000);

// ×¢Ò⣬ÕâÀïÒªÌîд·þÎñÆ÷³ÌÐò£¨TCPServer³ÌÐò£©ËùÔÚ»úÆ÷µÄIPµØÖ·

// Èç¹ûÄãµÄ¼ÆËã»úûÓÐÁªÍø£¬Ö±½ÓʹÓÃ127.0.0.1¼´¿É

servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)

{

printf(" Failed connect() \n");

return 0;

}

// ·¢ËÍÊý¾Ý

send(s,"dddd",sizeof("dddd"),0);

// ½ÓÊÕÊý¾Ý

char buff[256];

int nRecv = ::recv(s, buff, 256, 0);

if(nRecv > 0)

{

buff[nRecv] = '\0';

printf(" ½ÓÊÕµ½Êý¾Ý£º%s", buff);

}

// ¹Ø±ÕÌ×½Ú×Ö

::closesocket(s);

::WSACleanup();

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐