C iOcp
#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的更多相关文章
- IOCP Internals
Buffer Type Buffer I/O 针对Buffer I/O的请求,系统会为其分配一个非换页内存作为缓存区,其大小等同于I/O请求的缓存区大小.对于写操作,I/O管理器在创建IRP时,将请求 ...
- iocp 小例子
2016-08-3116:44:09 server 端 /******************************************************************* aut ...
- 简单说一个IOCP不好的地方
感谢rulary的指正!博文中我对IOCP的理解是有误的,正确的方式请见评论区rulary的回复! 由于项目实际设计的需要,最终IO事件处理没有采用IOCP,而是采用了NT6.0引入的WSAPoll, ...
- IOCP和WSA异步协同客户端版
有些小伙伴看了之前发的WIN平台下IOCP和WSA异步协同处理SOCKET后有些疑惑,所以就画了个简易流程图+架构图发上来给小伙伴参考 简单说,WSA异步控制CONNECT,IOCP控制WSASend ...
- windows WSABUF 结构在IOCP 中应用时两个成员变量的意义
WSABUF 结构的原型如下: typedef struct __WSABUF { u_long len; char FAR *buf; } WSABUF, *LPWSABUF; 该结构在IOCP 中 ...
- IOCP入门
完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...
- iocp还是select
上一个项目libevent应该是select,现在libuv是iocp,都知道Windows下iocp比select效率高,boost asio 也是iocp,但具体使用select和iocp发现没有 ...
- 再谈select, iocp, epoll,kqueue及各种I/O复用机制
原文:http://blog.csdn.net/shallwake/article/details/5265287 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonbl ...
- TCP协议下大数据传输IOCP乱序问题
毕业后稀里糊涂的闭门造车了两年,自己的独立博客也写了两年,各种乱七八糟,最近准备把自己博客废了,现在来看了下这两年写的对我来说略微有点意义的文章只此一篇,转载过来以作留念. 写的很肤浅且凌乱,请见谅. ...
- 高性能完成端口socket服务(IOCP)
1. Winsock IO模型之IOCP模型 来自csdn blog,版权声明:本文为博主原创文章,未经博主允许不得转载. 我这里记录下,不算转载吧 http://blog.csdn.net/lost ...
随机推荐
- MySqL触发器以及常用转换函数注意事项
1,触发器(http://www.cnblogs.com/zzwlovegfj/archive/2012/07/04/2576989.html) 1.MYSQL中触发器中不能对本表进行 i ...
- 关于su和su -的区别
关于su和su -的区别,切换用户是可以使用su tom或者su - tom来实现,但是两者有区别,su只是切换身份,但shell环境仍然是原用户的shell,su -是连用户的shell环境一起切换 ...
- Java语言导学笔记 Chapter 9 IO
java.io 9.1.1 字符流 Reader为读取器(reader)提供API和部分实现,读取器是读取16位字符的流: Writer为写出器(writer)提供API和部分实现,写出器是写16位字 ...
- JVM学习之实例分析JVM安全体系
转自:http://www.importnew.com/17093.html,感谢分享 类加载器的作用就是将真实的class文件根据位置将该Java类的字节码装入内存,并生成对应的Class对象.用户 ...
- JS的匿名函数和递归应用
今天有项目需要用到JS的递归,开始按照php的实现方法,发现不行,后来只能使用arguments.callee. 简单的例子,如下 var act = 'if(num <= 1){return ...
- APサーバ
GlassFish GlassFish 是一款强健的商业兼容应用服务器,达到产品级质量,可免费用于开发.部署和重新分发. 简介 GlassFish 是用于构建 Java EE 5应用服务器的开源开发项 ...
- js创建对象的几种常用方式小结
第一种模式:工厂方式 var lev=function(){ return "666"; }; function Parent(){ var Child = new Object ...
- numpy 札记
transpose 在处理caffe读入的图片数据时,需要将原始图片的数据 H*W*3(height*width*RGB) 转换为 3*H*W(RGB*heigth*width) 需要用到numpy的 ...
- SQL Server 权限的分类
SQL Server 的权限可以分三类 第一类 server 层面上的: select * from sys.fn_builtin_permissions(default) where class_d ...
- arcEngine添加标注(上)
arcEngine添加标注有3个技术点:1,获得图层的属性字段:2,初始化符号显示控件:3,添加标注. 获得图层的属性字段: //每个图层都是一个表的图形化显示,ILayer跟ITale可以互相转 ...