Windows上io复用-完成端口(iocp)
简单认识iocp
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 1024
typedef struct tagPER_HANDLE_DATA
{
SOCKET socket;
SOCKADDR_STORAGE clientAddr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
typedef struct tagPER_IO_DATA
{
OVERLAPPED overlappend;
WSABUF dataBuf;
char buffer[1024];
int bufferLen;
int OperationType; //读写标志
}PER_IO_DATA, *LPPER_IO_DATA;
DWORD WINAPI ServerWorkFunc(LPVOID lpParam);
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("agrc < 2\n");
abort();
}
WSADATA wsadata;
WORD socket_verson = MAKEWORD(2, 2); //定义版本
if (WSAStartup(socket_verson, &wsadata) != 0) //
{
fprintf(stderr, "socket init failed!\n");
abort();
}
int port = atoi(argv[1]);
SOCKADDR_IN server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
HANDLE completionPort;
SYSTEM_INFO systemInfo;
SOCKET serverSocket;
//完成端口
//1.创建一个完成端口
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
//2.获取cpu个数
GetSystemInfo(&systemInfo);
//3.根据cpu个数创建工作线程
for (int i = 0; i < systemInfo.dwNumberOfProcessors; i++)
{
HANDLE threadHandle;
threadHandle = CreateThread(NULL, 0, ServerWorkFunc, completionPort, 0, NULL);
CloseHandle(threadHandle);
}
//4.创建一个sokcet,并进行绑定和监听
serverSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
int bind_result = bind(serverSocket, (SOCKADDR *)&server_addr, sizeof(server_addr));
if (bind_result == SOCKET_ERROR)
{
fprintf(stderr, "socket bind failed!\n");
abort();
}
int listen_result = listen(serverSocket, 10);
if (listen_result == SOCKET_ERROR)
{
fprintf(stderr, "socket listen error!\n");
abort();
}
for (;;)
{
PER_HANDLE_DATA* perHandleData = NULL;
SOCKADDR_IN saRemote;
SOCKET clientSocket;
int remoteLen;
remoteLen = sizeof(saRemote);
clientSocket = accept(serverSocket, (SOCKADDR *)&saRemote, &remoteLen);
if (clientSocket == SOCKET_ERROR)
{
printf("client socket is null\n");
continue;
}
perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
perHandleData->socket = clientSocket;
memcpy(&perHandleData->clientAddr, &saRemote, remoteLen);
//7.将socket和完成端口进行关联
CreateIoCompletionPort((HANDLE)clientSocket, completionPort, (DWORD)perHandleData, 0);
//开始接受socket 处理i/o
//使用重叠i/o,在新建的socket投递一个或多个异步
//WSARecv或WSASend请求,在这些i/o请求完成之后,工作线程会为i/o请求提供服务
static int DATA_BUFSIZE = 4096;
DWORD recvBytes = 0;
DWORD flags = 0;
LPPER_IO_DATA perIoData = NULL;
perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
ZeroMemory(&(perIoData->overlappend), sizeof(OVERLAPPED));
perIoData->dataBuf.len = 1024;
perIoData->dataBuf.buf = perIoData->buffer;
perIoData->OperationType = 0; //读
WSARecv(perHandleData->socket,
&(perIoData->dataBuf), 1,
&recvBytes,
&flags,
&(perIoData->overlappend),
NULL);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
DWORD WINAPI ServerWorkFunc(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;
DWORD bRet;
for (;;)
{
//等待完成端口通知
bRet = GetQueuedCompletionStatus(completionPort,
&bytesTransferred,
(PULONG_PTR)&perHandleData,
(LPOVERLAPPED *)&lpOverlapped,
INFINITE);
//根据CONTAINING_RECORD宏,计算类型指针地址
//第一个参数是类型的成员的指针地址
//第二个参数是类型
//第三个参数是类型中成员名称
perIoData = (LPPER_IO_DATA)CONTAINING_RECORD(lpOverlapped, PER_IO_DATA, overlappend);
if (bytesTransferred == 0)
{
closesocket(perHandleData->socket);
GlobalFree(perHandleData);
GlobalFree(perIoData);
continue;
}
//打印数据
printf("%s\n", perIoData->dataBuf.buf);
flags = 0;
ZeroMemory(&(perIoData->overlappend), sizeof(OVERLAPPED));
perIoData->dataBuf.len = 1024;
perIoData->dataBuf.buf = perIoData->buffer;
perIoData->OperationType = 0;
WSARecv(perHandleData->socket,
&(perIoData->dataBuf),
1,
&recvBytes,
&flags,
&(perIoData->overlappend),
NULL);
}
return 0;
}
秋风
2017-04-23