I/O完成端口(IOCP)
服务器:
#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std; // 单句柄数据
typedef struct tagPER_HANDLE_DATA
{
SOCKET Socket;
SOCKADDR_STORAGE ClientAddr;
// 将和这个句柄关联的其他有用信息,尽管放在这里面吧 }PER_HANDLE_DATA, *LPPER_HANDLE_DATA; // 但I/O 操作数据
typedef struct tagPER_IO_DATA
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
char buffer[];
int BufferLen;
int OperationType; // 可以作为读写的标志,为简单,我忽略了
}PER_IO_DATA, *LPPER_IO_DATA; //线程函数
DWORD WINAPI ServerWorkerThread(LPVOID lpParam); DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD BytesTransferred;
LPOVERLAPPED lpOverlapped;
LPPER_HANDLE_DATA PerHandleData = NULL;
LPPER_IO_DATA PerIoData = NULL;
DWORD SendBytes;
DWORD RecvBytes;
DWORD Flags;
BOOL bRet = FALSE; while (TRUE) //无限循环
{
bRet = GetQueuedCompletionStatus(CompletionPort,&BytesTransferred,(PULONG_PTR)&PerHandleData,(LPOVERLAPPED*)&lpOverlapped,INFINITE); // 检查成功的返回,这儿要注意使用这个宏CONTAINING_RECORD
PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(lpOverlapped,PER_IO_DATA,Overlapped);
// 先检查一下,看看是否在套接字上已有错误发生 if ( == BytesTransferred)
{
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
} // 数据处理
char sendBuf[];
sprintf(sendBuf,"Welcome %s to %d %d \n",PerIoData->DataBuf.buf,PerHandleData->Socket,::GetCurrentThreadId());
send(PerHandleData->Socket,sendBuf,strlen(sendBuf)+,);
//WSASend()
/*DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
for(i=0; i < SEND_COUNT ;i++) {
WSASend(PerHandleData->Socket, &DataBuf, 1, &SendBytes, 0, &SendOverlapped, NULL); */ // 成功了!!!这儿就收到了来自客户端的数据
cout << PerIoData->DataBuf.buf << ::GetCurrentThreadId() << endl; Flags = ;
// 为下一个重叠调用建立单I/O 操作数据
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = ;
PerIoData->DataBuf.buf = PerIoData->buffer;
PerIoData->OperationType = ; // read WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
}
return ;
} int main(int argc, _TCHAR* argv[])
{
//头部申明
HANDLE CompletionPort;
WSADATA wsd;
SYSTEM_INFO SystemInfo;
SOCKADDR_IN InternetAddr;
SOCKET Listen; // 加载WinSock2.2
WSAStartup(MAKEWORD(, ), &wsd); // 1.创建一个I/O 完成端口
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,,); // 2.确定系统中有多少个处理器
GetSystemInfo(&SystemInfo); // 3.基于系统中可用的处理器数量创建工作器线程
for (int i = ; i < int(SystemInfo.dwNumberOfProcessors * ); ++i)
{
HANDLE ThreadHandle;
// 创建一个服务器的工作器线程,并将完成端口传递到该线程
ThreadHandle = CreateThread(NULL,,ServerWorkerThread,CompletionPort,,NULL);
CloseHandle(ThreadHandle);
} // 4.创建一个监听套接字,以下的套路都是固定的。
Listen = WSASocket(AF_INET,SOCK_STREAM,,NULL,,WSA_FLAG_OVERLAPPED); //绑定和监听
InternetAddr.sin_family = PF_INET;
InternetAddr.sin_port = htons();
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(Listen, (SOCKADDR*)&InternetAddr, sizeof(InternetAddr));
listen(Listen, ); //无限循环
BOOL b = TRUE;
while (b)
{
PER_HANDLE_DATA * PerHandleData = NULL;
SOCKADDR_IN saRemote;
SOCKET Accept;
int RemoteLen;
// 5.接收连接,并分配完成端口,这儿可以用AcceptEx 来代替,以创
// 建可伸缩的Winsock 应用程序。
RemoteLen = sizeof(saRemote);
Accept = accept(Listen, (SOCKADDR*)&saRemote, &RemoteLen); // 6.创建用来和套接字关联的单句柄数据信息结构
PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)); //cout << "Socket number " << Accept << " connected" << endl; PerHandleData->Socket = Accept;
memcpy(&PerHandleData->ClientAddr, &saRemote, RemoteLen); // 7.将接受套接字和完成端口关联起来
CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,); // 开始在接受套接字上处理I/O
// 使用重叠I/O 机制,在新建的套接字上投递一个或多个异步
// WSARecv 或 WSASend 请求。这些I/O 请求完成后,工作者线程
// 会为I/O 请求提供服务,之后就可以坐享其成了
static int const DATA_BUFSIZE = ;
DWORD RecvBytes = ;
DWORD Flags = ; // 单I/O 操作数据
LPPER_IO_DATA PerIoData = NULL;
PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.len = ;
PerIoData->DataBuf.buf = PerIoData->buffer;
PerIoData->OperationType = ; // read
WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
} return ;
}
客户端:
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h> void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err; wVersionRequested = MAKEWORD( , ); err = WSAStartup( wVersionRequested, &wsaData );
if ( err != ) {
return;
} if ( LOBYTE( wsaData.wVersion ) != ||
HIBYTE( wsaData.wVersion ) != ) {
WSACleanup( );
return;
} while (true)
{
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,); SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons();
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); send(sockClient,"This is lisi",strlen("This is lisi")+,); char recvBuf[];
recv(sockClient,recvBuf,,);
printf("%s\n",recvBuf); closesocket(sockClient);
} WSACleanup();
}
I/O完成端口(IOCP)的更多相关文章
- DELPHI中完成端口(IOCP)的简单分析(4)
DELPHI中完成端口(IOCP)的简单分析(4) 在我以前写的文章中,一直说的是如何接收数据.但是对于如何发送数据却一点也没有提到.因为从代码量上来说接收的代码要比发送多很多.今天我就来写一下如 ...
- DELPHI中完成端口(IOCP)的简单分析(3)
DELPHI中完成端口(IOCP)的简单分析(3) fxh7622关注4人评论7366人阅读2007-01-17 11:18:24 最近太忙,所以没有机会来写IOCP的后续文章.今天好不容易有 ...
- DELPHI中完成端口(IOCP)的简单分析(2)
DELPHI中完成端口(IOCP)的简单分析(2) 今天我写一下关于DELPHI编写完成端口(IOCP)的工作者线程中的东西.希望各位能提出批评意见.上次我写了关于常见IOCP的代码,对于IOCP ...
- DELPHI中完成端口(IOCP)的简单分析(1)
DELPHI中完成端口(IOCP)的简单分析(1) 用DELPHI开发网络代码已经有一段时间了! 我发现在网上用VC来实现完成端口(IOCP)的代码很多,但是使用DELPHI来实现的就比较少了.对 ...
- 完成端口iocp——在螺丝壳里做道场
WINDOWS 2000以后的操作系统才支持IOCP.WINSOCK2.0才支持IOCP. 首先要有一个WINSOCK2.PAS的WINSOCK2.0接口调用声明单元. WINSOCK的版本号: WI ...
- 【windows核心编程】IO完成端口(IOCP)复制文件小例前简单说明
1.关于IOCP IOCP即IO完成端口,是一种高伸缩高效率的异步IO方式,一个设备或文件与一个IO完成端口相关联,当文件或设备的异步IO操作完成的时候,去IO完成端口的[完成队列]取一项,根据完成键 ...
- 完成端口IOCP详解
修改自: http://blog.csdn.net/piggyxp/article/details/6922277 ps: 原作者很厉害了, 把一个iocp模型讲解的这么形象,不过在实践过程中发现一些 ...
- TCP服务器并发编程构架:完成端口IOCP模式
windows下socket网络编程模式:IOCP 完成端口 1)IOCP异步事件的获取放到操作系统的网络驱动层来处理,实际上反而是降低了编程难度, 2)同时对于多线程的并发调度,也放到操作系统级别来 ...
- 套接字I/O模型-完成端口IOCP
“完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和W ...
- 完成端口(IOCP)怎么判断某个连接是否断开
完成端口函数: BOOL GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytes, PULONG_PTR l ...
随机推荐
- 剑指Offer——链表中倒数第k个节点
Question 输入一个链表,输出该链表中倒数第k个结点. Solution 一种想法就是扫描两边,第一遍求出总的节点个数,第二遍从头开始走n-k个 第二种思想类似于fast-slow指针的方法,f ...
- [转载]spring security 的 logout 功能
原文地址:security 的 logout 功能">spring security 的 logout 功能作者:sumnny 转载自:http://lengyun3566.iteye ...
- Pycharm更换pip源为国内
Python里的pip是官方自带的源,国内使用pip安装的时候十分缓慢,所以最好是更换成中国国内的源地址. 目前国内靠谱的 pip 镜像源有: 清华: https://pypi.tuna.tsingh ...
- read_excel
read_excel默认把第一行作为各个列名, 用headers=None,读取表时,可以让第一行不为列名. 而不是names,col之类的参数
- GreenDao 多表事务操作
场景:Android APP多表操作事务管理 使用Android自带的sql操作类操作的时候需要手动处理事务,使用GreenDao的时候不用管了,啥都处理好了.但是,如果是多表操作的话,怎么统一管理事 ...
- spring: 创建环绕通知
package ch2.test; public interface Performance { void perform(); } package ch2.test; import org.aspe ...
- WPF/WP/Silverlight/Metro App代码创建动画的思路
在2010年之前,我都是用Blend创建动画,添加触发器实现自动动画,后来写成代码创建的方式.如今Blend已经集成到Visual Studio安装镜像中了,最新的VS2015安装,Blend的操作界 ...
- SQL1221N The Application Support Layer heap cannot be allocated. SQLSTATE=57011
不能分配“应用程序支持层“堆 内存不足(系统中可用的调页空间量或交换空间量或系统中可用的物理内存量),可能会导致问题,并提示如下错误信息: SQL1221N The Application Supp ...
- Git_学习_07_ 推送修改到远端
一.操作流程 多人协作时,若自己的本地代码有了修改,想提交自己的代码,就需要按照以下步骤操作: 1.确认修改正确 使用以下命令,查看有哪些是自己未提交的代码 git status 2.拉取远程最新代码 ...
- AMD 规范使用总结
转自:http://www.jianshu.com/p/9b44a1fa8a96 AMD模式 define和require这两个定义模块.调用模块的方法,合称为AMD模式.它的模块定义的方法非常清晰, ...