一 个 封 装 了 IOCP 的 DLL

======================= 一 个 封 装 了 IOCP 的 DLL ====================================

设计想法:
 1、IOCP的DLL实现内存自制,既内存DLL自我管理,用户申请内存,用户释放,DLL的内存,用户不得释放
 2、用户至少需要提供三个LPTHREAD_START_ROUTINE类型的指针,用户处理接收数据、接受客户端连接、以及用户释放连接等事件
    当然,也可以将传入NULL表示不处理对应事件。此外,用户也可以选择是否处理发送成功消息(并没处理发送失败事件,可
    以考虑未来版本增加),在每次处理事件结束后,IOCP的DLL不保证数据仍然可用,如果用户对那些信息感兴趣,应该自己
    保持一份信息!
设计细节:
 1、IOCP初始化时,创建一个用于接收客户端连接的线程,此线程会一直阻塞在accept函数上,直到有新连接进来或者accept被打断,
    如果有新连接到来,将在堆上创建一个PER_HANDLE_DATA类型的结构,并包含两段内存(一段用于此socket的接收数据缓冲,另一
    段用户此socket的发送缓冲),此结构在中断连接后释放,用户不需要管理。
 2、IOCP初始化时,亦同时创建N个(N 等于当前机器CPU个数)的工作线程,这几个线程负责IOCP DLL的大部分工作(并将调用创建初始
    给出的事件处理函数,并将对应的PER_HANDLE_DATA的地址传给事件处理函数)。具体看代码和示例代码
 3、IOCP初始化时,还将创建一个垃圾回收线程,用户处理垃圾回收,因为在工作线程得知连接中断后,并不是马上释放内存,
    而是将数据放入垃圾站,由垃圾回收线程进行回收
 4、用户delete iocp时,iocp会等待以上线程均安全退出,并中断和释放当前仍在线的连接,然后安全退出。
已知BUG:
 1、垃圾回收线程,仍然无法保证不释放仍在使用的内存(尽管概率很小)

额外说明:
 1、毕设用的IOCP,未能做大量测试,可能存在未知BUG,如果发现BUG,请按以下联系方式联系本人,不甚感激!!
 2、特别注意,IOCP不保证所调用的事件处理函数是线程安全的,这部分应该有用户自行保证!
 3、最新更新,请留意  svn://svnhost.cn/IOCP_DLL
联系方式:
 Email:helloripple@qq.com
 QQ:271547131
 
 Ripple
 2010年5月6日
 于福州大学

IOCP(Input/Output Completion Port)是一种高效的异步I/O模型,可用于实现高性能的服务器。在Windows系统中,可以使用IOCP API来创建一个IOCP服务器。 下面是一个简单的IOCP服务器的示例代码: ```c #include <stdio.h> #include <winsock2.h> #include <windows.h> #define PORT 12345 #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 typedef struct { OVERLAPPED overlapped; SOCKET socket; WSABUF wsaBuf; CHAR buffer[BUFFER_SIZE]; DWORD bytesTransferred; DWORD flags; } PER_IO_DATA, *LPPER_IO_DATA; VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransfered, LPOVERLAPPED lpOverlapped, DWORD dwFlags); int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建监听套接字 SOCKET listenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (listenSocket == INVALID_SOCKET) { printf("Error creating listen socket: %d\n", WSAGetLastError()); return 1; } // 绑定端口号 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_port = htons(PORT); if (bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { printf("Error binding port: %d\n", WSAGetLastError()); return 1; } // 监听连接 if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) { printf("Error listening: %d\n", WSAGetLastError()); return 1; } // 创建IOCP句柄 HANDLE iocpHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (iocpHandle == NULL) { printf("Error creating IOCP handle: %d\n", GetLastError()); return 1; } // 将监听套接字绑定到IOCP句柄上 if (CreateIoCompletionPort((HANDLE)listenSocket, iocpHandle, (ULONG_PTR)listenSocket, 0) == NULL) { printf("Error binding listen socket to IOCP handle: %d\n", GetLastError()); return 1; } // 创建客户端套接字 SOCKET clientSockets[MAX_CLIENTS]; for (int i = 0; i < MAX_CLIENTS; i++) { clientSockets[i] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (clientSockets[i] == INVALID_SOCKET) { printf("Error creating client socket: %d\n", WSAGetLastError()); return 1; } } // 接受连接 for (;;) { SOCKADDR_IN clientAddr; int clientAddrLen = sizeof(clientAddr); SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&clientAddr, &clientAddrLen); if (clientSocket == INVALID_SOCKET) { printf("Error accepting connection: %d\n", WSAGetLastError()); continue; } // 将客户端套接字绑定到IOCP句柄上 if (CreateIoCompletionPort((HANDLE)clientSocket, iocpHandle, (ULONG_PTR)clientSocket, 0) == NULL) { printf("Error binding client socket to IOCP handle: %d\n", GetLastError()); closesocket(clientSocket); continue; } // 分配PER_IO_DATA结构体 LPPER_IO_DATA perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA)); perIoData->socket = clientSocket; perIoData->wsaBuf.buf = perIoData->buffer; perIoData->wsaBuf.len = BUFFER_SIZE; perIoData->flags = 0; // 开始接收数据 DWORD bytesRecv; if (WSARecv(clientSocket, &perIoData->wsaBuf, 1, &bytesRecv, &perIoData->flags, &perIoData->overlapped, CompletionRoutine) == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { printf("Error starting receive: %d\n", WSAGetLastError()); GlobalFree(perIoData); closesocket(clientSocket); continue; } } } // 关闭监听套接字 closesocket(listenSocket); // 释放资源 for (int i = 0; i < MAX_CLIENTS; i++) { closesocket(clientSockets[i]); } WSACleanup(); return 0; } VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransfered, LPOVERLAPPED lpOverlapped, DWORD dwFlags) { LPPER_IO_DATA perIoData = (LPPER_IO_DATA)lpOverlapped; if (dwErrorCode == 0 && dwBytesTransfered > 0) { printf("Received %d bytes from socket %d\n", dwBytesTransfered, perIoData->socket); } else { printf("Error receiving data: %d\n", dwErrorCode); } GlobalFree(perIoData); closesocket(perIoData->socket); } ``` 在这个示例中,我们首先创建一个监听套接字,绑定端口号并开始监听连接。然后,我们创建一个IOCP句柄,并将监听套接字绑定到IOCP句柄上。 接下来,我们创建一些客户端套接字,并在接受连接时将它们绑定到IOCP句柄上。每当有一个客户端连接到服务器时,我们为其分配一个PER_IO_DATA结构体,并使用WSARecv函数开始接收数据。在WSARecv函数中,我们将PER_IO_DATA结构体的地址传递给了overlapped参数,这样就可以在数据接收完成后得到它。 当数据接收完成后,系统会调用CompletionRoutine回调函数。在这个函数中,我们可以检查数据接收是否成功,并释放PER_IO_DATA结构体和客户端套接字。 需要注意的是,在IOCP服务器中,所有的I/O操作都是异步的,因此我们需要使用OVERLAPPED结构体来描述每一个I/O操作,并在每个I/O操作完成后启动回调函数。在这个示例中,我们使用了PER_IO_DATA结构体来扩展OVERLAPPED结构体,并包含了一些额外的信息,例如套接字、接收缓冲区等。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值