IOCP模型TCP服务器
主线程创建监听套接字,创建额外工作线程,关联IOCP,负责等待和接受到来的连接。
调用GetQueuedCompletionStatus函数,函数返回:
1 调用失败
2 套接字被对方关闭
3 请求成功完成
程序首先定义per-handle per-IO的操作数据的结构类型
#define BUFFER_SIZE 1024 typedef struct _PER_HANDLE_DATA{ SOCKET s; sockaddr_in addr; }PER_HANDLE_DATA,*PPER_HANDLE_DATA; typedef struct _PER_IO_DATA{ OVERLAPPED ol; char buf[BUFFER_SIZE]; int nOperationType; #define OP_READ 1 #define OP_WRITE 2 #define OP_ACCEPT 3 }PER_IO_DATA,*PPER_IO_DATA;
主要过程:
1 主线程创建完成端口对象,创建工作线程处理完成端口对象中的事件
2 创建监听套接字,开始监听服务器端口
3 进入无限循环,处理到来的请求
1)调用accept函数等待接受未决的连接请求 2)创建一个per-handle数据 3)投递一个接收请求
实现代码:
void main() { int nPort = 4567; HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); ::CreateThread(NULL,0,ServerThread,(LPVOID)hCompletion,0,0); SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN si; si.sin_family = AF_INET; si.sin_port = htons(nPort); si.sin_addr.S_un.S_addr = INADDR_ANY; ::bind(sListen,(sockaddr*)&si,sizeof(si)); ::listen(sListen,5); while(TRUE){ //等待接收未决的请求 SOCKADDR_IN saRemote; int nRemoteLen = sizeof(saRemote); SOCKET sNew = ::accept(sListen,(sockaddr*)&saRemote,&nRemoteLen); //创建per-handle PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)); pPerHandle->s = sNew; memcpy(&pPerHandle->addr,&saRemote,nRemoteLen); ::CreateIoCompletionPort((HANDLE)pPerHandle->s,hCompletion,(DWORD)pPerHandle,0); //投递一个接收请求 PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR,sizeof(PER_IO_DATA)); pPerIO->nOperationType = OP_READ; WSABUF buf; buf.buf = pPerIO->buf; buf.len = BUFFER_SIZE; DWORD dwRecv; DWORD dwFlags = 0; ::WSARecv(pPerHandle->s,&buf,1,&dwRecv,&dwFlags,&pPerIO->ol,NULL);//接收投递求 } } DWORD WINAPI ServerThread(LPVOID lpParam{ HANDLE hCompletion = (HANDLE)lpParam; DWORD dwTrans; PPER_HANDLE_DATA pPerHandle; PPER_IO_DATA pPerIO; while(TRUE){ BOOL bOK = ::GetQueuedCompletionStatus(hCompletion,&dwTrans,(LPDWORD)&pPerHandle,(LPOVERLAPPED*)&pPerIO,WSA_INFINITE); if(!bOK) { ::closesocket(pPerHandle->s); ::GlobalFree(pPerHandle); ::GlobalFree(pPerIO); continue; } if(dwTrans == 0 && (pPerIO->nOperationType==OP_READ||pPerIO->nOperationType==OP_WRITE)) { ::closesocket(pPerHandle->s); ::GlobalFree(pPerHandle); ::GlobalFree(pPerIO); continue; } switch(pPerIO->nOperationType) { case OP_READ: { pPerIO->buf[dwTrans] = '\0'; printf(pPerIO->buf); WSABUF buf; buf.buf = pPerIO->buf; buf.len = BUFFER_SIZE; pPerIO->nOperationType = OP_READ; DWORD nFlags = 0; ::WSARecv(pPerHandle->s,&buf,1,&dwTrans,&nFlags,&pPerIO->ol,NULL); } break; case OP_WRITE: case OP_ACCEPT: break; } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?