#include   <winsock2.h>
//#include <windows.h>
#include <stdio.h> #define PORT 5150
#define DATA_BUFSIZE 8192 typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA; typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA; DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID); int main(void)
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret; if ((Ret = WSAStartup(0x0202, &wsaData)) != )
{
printf("WSAStartup失败了,错误信息如下: %d\n", Ret);
return;
} // 设置一个I/O完成端口. if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, , )) == NULL)
{
printf( "CreateIoCompletionPort 失败了,错误信息如下: %d\n", GetLastError());
return;
} // 测试系统中有多少cpu处理器 GetSystemInfo(&SystemInfo); // 基于系统可用的处理器创建工作线程,为每个处理器创建连个线程 for(i = ; i < SystemInfo.dwNumberOfProcessors * ; i++)
{
HANDLE ThreadHandle; // 创建一个服务端线程并且传递一个完成端口给这个线程. if ((ThreadHandle = CreateThread(NULL, , ServerWorkerThread, CompletionPort,
, &ThreadID)) == NULL)
{
printf("CreateThread()发生了如下错误: %d\n", GetLastError());
return;
}
else
{printf("创建了一个完成端口.\n");
}
// 关闭 thread句柄
CloseHandle(ThreadHandle);
} // 创建一个监听套接字 if ((Listen =WSASocket(AF_INET, SOCK_STREAM, , NULL,,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() 发生了如下错误: %d\n", WSAGetLastError());
return;
}
else
{printf("创建监听套接字成功\n");}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT); if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind()端口或IP时发生了如下错误: %d\n", WSAGetLastError());
return;
}
else
{printf("绑定端口%d成功\n",PORT);}
// 准备socket 用来监听 if (listen(Listen, ) == SOCKET_ERROR)
{
printf("listen() 发生了如下错误 %d\n", WSAGetLastError());
return;
}
else
{printf("预处理成功,开始在端口 %d 处监听...\n",PORT);}
//接受连接并且交给完成端口处理 while(TRUE)
{
if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, )) == SOCKET_ERROR)
{
printf("WSAAccept() 发生了如下错误: %d\n", WSAGetLastError());
return;
} // 创建一个套接字信息结构体去联系起来socket
if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlobalAlloc() 发生了如下错误: %d\n", GetLastError());
return;
} // 将接受到的套接字与原始的完成端口联系起来. printf("号码为 %d 的socket连接上了\n", Accept);
PerHandleData->Socket = Accept; if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
) == NULL)
{
printf("CreateIoCompletionPort 发生了如下错误: %d\n", GetLastError());
return;
} // 创建每一个I/O 套接字信息结构体去和下面被调用的 to associate with the
// WSARecv 连接. if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() 发生了如下错误: %d\n", GetLastError());
return;
}
else{printf("接收了一个连接\n");}
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->BytesSEND = ;
PerIoData->BytesRECV = ;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer; Flags = ;
if (WSARecv(Accept, &(PerIoData->DataBuf), , &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() 发生了如下错误: %d\n", WSAGetLastError());
return;
}
}
}
} DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags; while(TRUE)
{ if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == )
{
printf("GetQueuedCompletionStatus 发生了如下错误: %d\n", GetLastError());
return ;
} //首先检查一下去套接字看是否在上发生了错误并且如果发生了错误就关闭套接
//字并且清除与套接字连接的 SOCKET_INFORMATION结构信息体
if (BytesTransferred == )
{
printf("正在关闭socket %d\n", PerHandleData->Socket); if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
printf("closesocket() 发生了如下错误: %d\n", WSAGetLastError());
return ;
} GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
//检查如果 BytesRECV字段等于0,这就意味着一个 WSARecv调用刚刚完成了所以从完成的WSARecv()调用中
//用BytesTransferred值更新 BytesRECV字段
if (PerIoData->BytesRECV == )
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = ;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
} if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{
//发布另外一个 WSASend()请求
//既然WSASend()不是 gauranteed去发送所有字节的请求
//继续调用 WSASend()发送直到所有收到的字节被发送 ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND; if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), , &SendBytes, ,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() 发生了如下错误: %d\n", WSAGetLastError());
return ;
}
}
}
else
{
PerIoData->BytesRECV = ;
//现在没有更多的字节发送过去用来post另外一个WSARecv()请求 Flags = ;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer; if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), , &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() 发生了如下错误: %d\n", WSAGetLastError());
return ;
}
}
}
}
}

C iOcp的更多相关文章

  1. IOCP Internals

    Buffer Type Buffer I/O 针对Buffer I/O的请求,系统会为其分配一个非换页内存作为缓存区,其大小等同于I/O请求的缓存区大小.对于写操作,I/O管理器在创建IRP时,将请求 ...

  2. iocp 小例子

    2016-08-3116:44:09 server 端 /******************************************************************* aut ...

  3. 简单说一个IOCP不好的地方

    感谢rulary的指正!博文中我对IOCP的理解是有误的,正确的方式请见评论区rulary的回复! 由于项目实际设计的需要,最终IO事件处理没有采用IOCP,而是采用了NT6.0引入的WSAPoll, ...

  4. IOCP和WSA异步协同客户端版

    有些小伙伴看了之前发的WIN平台下IOCP和WSA异步协同处理SOCKET后有些疑惑,所以就画了个简易流程图+架构图发上来给小伙伴参考 简单说,WSA异步控制CONNECT,IOCP控制WSASend ...

  5. windows WSABUF 结构在IOCP 中应用时两个成员变量的意义

    WSABUF 结构的原型如下: typedef struct __WSABUF { u_long len; char FAR *buf; } WSABUF, *LPWSABUF; 该结构在IOCP 中 ...

  6. IOCP入门

    完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...

  7. iocp还是select

    上一个项目libevent应该是select,现在libuv是iocp,都知道Windows下iocp比select效率高,boost asio 也是iocp,但具体使用select和iocp发现没有 ...

  8. 再谈select, iocp, epoll,kqueue及各种I/O复用机制

    原文:http://blog.csdn.net/shallwake/article/details/5265287 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonbl ...

  9. TCP协议下大数据传输IOCP乱序问题

    毕业后稀里糊涂的闭门造车了两年,自己的独立博客也写了两年,各种乱七八糟,最近准备把自己博客废了,现在来看了下这两年写的对我来说略微有点意义的文章只此一篇,转载过来以作留念. 写的很肤浅且凌乱,请见谅. ...

  10. 高性能完成端口socket服务(IOCP)

    1. Winsock IO模型之IOCP模型 来自csdn blog,版权声明:本文为博主原创文章,未经博主允许不得转载. 我这里记录下,不算转载吧 http://blog.csdn.net/lost ...

随机推荐

  1. HTML界面JQuery ajax 返回200,但走Error方法

    原因是JSON拼装的有问题. 都需要放在双引号里面,或者修改dataType的类型为  "html". http://blog.csdn.net/imjcoder/article/ ...

  2. Linux Mysql 总结

    一:Error Code: . Access denied for user 'root'@'%' to database ① mysql -u root -p 进入到mysql中 ②SELECT h ...

  3. linux chmod使用说明

    chmod是用来改变一个目录的访问权限的,一般的方式是:chmod a+rwx 其中a代表全部,还有u[目录拥有者] ,g[目录拥有组],o[其他用户] r代表读,w代表写,x代表可以执行,对应数字权 ...

  4. Twisted No module named win32api

    安装twisted成功后,使用时抛错: No module named win32api 解决方案,需要安装 pywin32 下载地址: https://sourceforge.net/project ...

  5. javaEE简答题整理

    1. 什么是JavaEE?其编程思想是什么? JavaEE是一个标准的中间件体系结构,是企业分布式应用开发标准.JavaEE的编程思想是组件—容器. 2. 为什么提出JavaEE体系结构? (1)为满 ...

  6. codeforces 659C . Tanya and Toys 二分

    题目链接 将给出的已经有了的排序, 在前面加上0, 后面加上1e9+1. 然后对相邻的两项判断. 如果相邻两项之间的数的和小于m, 那么全都选上, m减去相应的值. 如果大于m, 那么二分判断最多能选 ...

  7. 转载:NSobject官方介绍

    概述: NSObject协议组对所有的Object-C下的objects都生效. 如果objects遵从该协议,就会被看作是first-class objects(一级类). 另外,遵从该协议的obj ...

  8. FAQ:Python环境变量配置

    Python安装安装成,需要配置环境变量: 默认情况下,在windows下安装python之后,系统并不会自动添加相应的环境变量.此时不能在命令行直接使用python命令. 1. 首先需要在系统中注册 ...

  9. linux的nohup命令的用法。

    在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会 用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台: /usr/local/mysql/bin/m ...

  10. C语言入门(8)——形参与实参

    对于带参数的函数,我们需要在函数定义中指明参数的个数和每个参数的类型,定义参数就像定义变量一样,需要为每个参数指明类型,并起一个符合标识符命名规则的名字.例如: #include <stdio. ...