服务器经典稳定版iocp,个人IOCP服务器例子解说

这里写两方面的解说,一方面,解说iocp内部处理情况(这部分以个人查考写的iocp服务器和客户端写的);一方面,参考libeventlibevent-1.4.4-iocp-3 大致调整给出一个比较标准的服务器和客户端例子。新手可以通过前部分获得建立iocp的基本理解;通过后部分建立自己(基于libevent)标准的iocp代码。

一、//先来建立自己的icop吧

1)自己的iocp服务器(MyIOCPServer.cpp)

#include "stdafx.h"

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

#include 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[1024];

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 (0 == BytesTransferred)

{

closesocket(PerHandleData->Socket);

GlobalFree(PerHandleData);

GlobalFree(PerIoData);

continue;

}

// 数据处理

char sendBuf[100];

sprintf(sendBuf,"Welcome %s to  %d %d \n",PerIoData->DataBuf.buf,PerHandleData->Socket,::GetCurrentThreadId());

send(PerHandleData->Socket,sendBuf,strlen(sendBuf)+1,0);

//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 = 0;

// 为下一个重叠调用建立单I/O 操作数据

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.len = 1024;

PerIoData->DataBuf.buf = PerIoData->buffer;

PerIoData->OperationType = 0; // read

WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);

}

return 0;

}

int main(int argc, _TCHAR* argv[])

{

//头部申明

HANDLE CompletionPort;

WSADATA wsd;

SYSTEM_INFO SystemInfo;

SOCKADDR_IN InternetAddr;

SOCKET Listen;

// 加载WinSock2.2

WSAStartup(MAKEWORD(2, 2), &wsd);

// 1.创建一个I/O 完成端口

CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

// 2.确定系统中有多少个处理器

GetSystemInfo(&SystemInfo);

// 3.基于系统中可用的处理器数量创建工作器线程

for (int i = 0; i < int(SystemInfo.dwNumberOfProcessors * 2); ++i)

{

HANDLE ThreadHandle;

// 创建一个服务器的工作器线程,并将完成端口传递到该线程

ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,NULL);

CloseHandle(ThreadHandle);

}

// 4.创建一个监听套接字,以下的套路都是固定的。

Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

//绑定和监听

InternetAddr.sin_family = PF_INET;

InternetAddr.sin_port = htons(6000);

InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(Listen, (SOCKADDR*)&InternetAddr, sizeof(InternetAddr));

listen(Listen, 5);

//无限循环

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,0);

// 开始在接受套接字上处理I/O

// 使用重叠I/O 机制,在新建的套接字上投递一个或多个异步

// WSARecv 或 WSASend 请求。这些I/O 请求完成后,工作者线程

// 会为I/O 请求提供服务,之后就可以坐享其成了

static int const DATA_BUFSIZE = 4096;

DWORD RecvBytes = 0;

DWORD Flags = 0;

// 单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 = 1024;

PerIoData->DataBuf.buf = PerIoData->buffer;

PerIoData->OperationType = 0; // read

WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);

}

return 0;

}

2)自己的iocp客户端(MyIOCPClient.cpp)

#include "stdafx.h"

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

#include

void main()

{

WORD wVersionRequested;

WSADATA wsaData;

int err;

wVersionRequested = MAKEWORD( 1, 1 );

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 ) {

return;

}

if ( LOBYTE( wsaData.wVersion ) != 1 ||

HIBYTE( wsaData.wVersion ) != 1 ) {

WSACleanup( );

return;

}

while (true)

{

SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

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(6000);

connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

send(sockClient,"This is lisi",strlen("This is lisi")+1,0);

char recvBuf[100];

recv(sockClient,recvBuf,100,0);

printf("%s\n",recvBuf);

closesocket(sockClient);

}

WSACleanup();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现一个IOCP(Input/Output Completion Port)服务器,需要按照以下步骤进行: 1. 创建一个监听套接字(listening socket)并绑定到本地IP地址和端口号上。 2. 创建一个完成端口(completion port)并将监听套接字与之关联。 3. 开始监听连接请求,当有客户端连接请求到达时,接收连接,创建一个新的套接字(client socket),并将其与完成端口关联。 4. 将新创建的套接字(client socket)加入到IOCP中,以便异步地接收客户端的数据请求。 5. 当客户端请求到达时,使用异步I/O操作,从套接字中读取数据,并将读取请求与完成端口关联。 6. 当读取完成时,将读取请求与处理请求的工作线程关联,并将读取到的数据传递给处理线程进行处理。 7. 处理线程完成数据的处理后,将处理结果写回客户端,使用异步I/O操作将写入请求与完成端口关联。 8. 当写入完成时,将写入请求与处理请求的工作线程关联,完成整个请求处理过程。 在实现IOCP服务器时,需要注意以下几点: 1. 应避免使用阻塞I/O操作,使用异步I/O操作以提高服务器的并发性能。 2. 应充分利用完成端口和线程池等技术,提高服务器的吞吐量和可扩展性。 3. 应实现适当的协议处理逻辑,以保证服务器能够正确地处理客户端请求。 4. 应对客户端请求进行适当的安全性检查,以确保服务器的安全运行。 5. 应实现适当的错误处理逻辑,以便及时发现和处理服务器中的错误和异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值