c/c++ TcpServer-IOCP管理模式
2018-02-15 11:09
274 查看
IOCP
1: IOCP: 是windows针对高性能服务器做的IO的管理模式,又叫完成端口;2: IOCP的核心模式:
1>提交请求;
2>等待结果;
3>继续提交请求;
3: 监听:
1>提交一个监听请求,使用完成端口来等待这个请求到来;
2>请求来了后,处理,继续提交请求;
4: 读取数据:
1>提交一个读取数据的请求。
2>请求完成后,处理完后继续提交;
5: 发送数据的请求:
1>提交一个发送数据的请求;
2>请求完成后,继续处理;
IOCP开发
1:配置IOCP开发环境:#include <WinSock2.h> #include <mswsock.h> #include <windows.h> #pragma comment(lib, "WSOCK32.lib ") #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "odbc32.lib") #pragma comment(lib, "odbccp32.lib")
2: 创建一个IOCP;
3: 提交一个IOCP的监听请求:
4: 提交读请求;
#include <stdio.h> #include <string.h> #include <stdlib.h> /* IOCP 只支持windows平台 Linux epoll */ #include <WinSock2.h> #include <MSWSock.h> #include <Windows.h> #pragma comment(lib,"WSOCK32.LIB") #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"odbc32.lib") #pragma comment(lib,"odbccp32.lib") // 非常重要的数据结构; enum{ IOCP_ACCEPT = 0, // 监听socket,接入请求; IOCP_RECV, // 读请求; IOCP_WRITE, // 写请求; }; // 接收数据的时候最大的buf大小; #define MAX_RECV_SIZE 8192 struct io_package{ // 自己定义的, 一定要在第一个就要用WSAOVERLAPPED 结构体;? // 所有的请求的等待,都是等在这个结构对象上的,必须是第一个; WSAOVERLAPPED overlapped; // 操作类型, 监听,读,写, IOCP_ACCPET, IOCP_RECV, IOCP_WRITE int opt; // 句柄,就是我们提交请求的句柄, accept的句柄或你读写请求的句柄 int accept_sock; // 结构体,配合读写数据的时候用的bufffer; WSABUF wsabuffer;// wsabuffer.buf = 内存;, wsabuffer.len = MAX_RECV_SIZE; // 定义了一个buf,这个buf就是整正的内存; char pkg[MAX_RECV_SIZE]; }; // 投递一个用户的请求; static void post_accept(SOCKET l_sock){ // step1: 分配一个io_package 数据结构; struct io_package* pkg = malloc(sizeof(struct io_package)); memset(pkg, 0, sizeof(struct io_package)); // 初始化好了接受数据的buf --> WSABUF pkg->opt = IOCP_ACCEPT; // 请求类型; pkg->wsabuffer.buf = pkg->pkg; pkg->wsabuffer.len = MAX_RECV_SIZE - 1; SOCKET client = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); int addr_size = (sizeof(struct sockaddr) + 16); pkg->accept_sock = client;// 创建一个socket,然后客户端连接进来后,就用这个socket和我们的客户端通讯; // 发送一个异步的请求,来接入客户端的连接; DWORD dwBytes = 0; AcceptEx(l_sock, client, pkg->wsabuffer.buf, 0, addr_size, addr_size, &dwBytes, &pkg->overlapped); } static void post_recv(SOCKET client_fd){ struct io_package* io_data = malloc(sizeof(struct io_package)); memset(io_data, 0, sizeof(struct io_package)); io_data->opt = IOCP_RECV; io_data->wsabuffer.buf=io_data->pkg; io_data->wsabuffer.len = MAX_RECV_SIZE - 1; io_data->accept_sock = client_fd; DWORD dwRecv = 0; DWORD dwFlgs = 0; int ret = WSARecv(client_fd, &(io_data->wsabuffer), 1, &dwRecv, &dwFlgs,&(io_data->overlapped),NULL ); } int main(int argc, char** argv){ // 如果你做socket那么必须要加上; WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); // step1:创建一个完成端口; HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (iocp == INVALID_HANDLE_VALUE){ goto failed; } // 创建我们的监听socket,开始监听 SOCKET l_sock = INVALID_SOCKET; l_sock = socket(AF_INET, SOCK_STREAM, 0); if (l_sock == INVALID_SOCKET){ goto failed; } struct sockaddr_in s_address; memset(&s_address, 0, sizeof(s_address)); s_address.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); s_address.sin_family = AF_INET; s_address.sin_port = htons(6080); if (bind(l_sock, (struct sockaddr*)&s_address, sizeof(s_address)) != 0){ goto failed; } if (listen(l_sock, SOMAXCONN) != 0){ goto failed; } // 让IOCP来管理我们的l_sock // 第三个参数,是用户传的自定义数据(一个指针带入进去),后面讲解; CreateIoCompletionPort((HANDLE)l_sock, iocp, (DWORD)0, 0); // 发送一个监听用户进来的请求; post_accept(l_sock);// 投递一个accpet接入请求; while (1){ DWORD dwTrans; DWORD udata; struct io_package* io_data; // 通过完成端口,来获得这个请求的结果; // 调用操作系统的API函数,查看,那个请求完成了; // 如果没有状态完成了,那么任务会挂起,等待; int ret = GetQueuedCompletionStatus(iocp,&dwTrans, &udata,(LPOVERLAPPED*)&io_data,WSA_INFINITE); if (ret == 0){ //意外 if (io_data){ if (io_data->opt == IOCP_RECV){ closesocket(io_data->accept_sock); free(io_data); } else if (io_data->opt == IOCP_ACCEPT){ free(io_data); post_accept(l_sock); } } continue; } if (dwTrans == 0 && io_data->opt == IOCP_RECV){ // 关闭socket发生了; closesocket(io_data->accept_sock); free(io_data); continue; } switch (io_data->opt) { case IOCP_ACCEPT: //接入第一个SOCKET; { //接入的client_sock int client_fd = io_data->accept_sock; int addr_size = (sizeof(struct sockaddr_in) + 16); struct sockaddr_in* l_addr = NULL; int l_len = sizeof(struct sockaddr_in); struct sockaddr_in* r_addr = NULL; int r_len = sizeof(struct sockaddr_in); GetAcceptExSockaddrs(io_data->wsabuffer.buf, 0,/*io_data->wsabuffer.len - addr_size * 2, */ addr_size, addr_size, (struct sockaddr**)&l_addr, &l_len, (struct sockaddr**)&r_addr,&r_len); // 将新进来的client_fd,也加入完成端口,来帮助管理完成的请求; // 第三个参数是用户自定义数据,你可以携带自己的数据结构,client_fd; CreateIoCompletionPort((HANDLE)client_fd, iocp, (DWORD)client_fd, 0); //投递一个读的请求 post_recv(client_fd); //重新投递一个接入客户端 free(io_data); post_accept(l_sock); } break; case IOCP_RECV: { //dwTrans 读到数据的大小; //soket,io_data->accept_sock; //Buf io_data->wsabuffer.buf io_data->pkg[dwTrans] = 0; printf("IOCP RECV %d %s\n", dwTrans, io_data->pkg); send(io_data->accept_sock, io_data->pkg, dwTrans, 0); //再来投递下一个请求 DWORD dwRecv = 0; DWORD dwFlgs = 0; int ret = WSARecv(io_data->accept_sock, &(io_data->wsabuffer), 1, &dwRecv, &dwFlgs, &(io_data->overlapped),NULL); } break; default: break; } } failed: if (l_sock){ goto failed; } if (iocp != INVALID_HANDLE_VALUE){ CloseHandle(iocp);//释放关闭端口 } WSACleanup(); return 0; }
服务端
客户端
相关文章推荐
- Linux TCP server系列(5)-select模式下的单进程server
- SQL Server Reporting Services本机模式下的权限管理
- C++ TCP Server
- ESP8266 station模式下建立client、server TCP连接
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之基础篇
- Iocp Tcp Server——G-Socket1.1 Demo源码(VC & Delphi)
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之前言篇
- c++ send tcp ___ server c# byte转结构
- C++ TCP Server
- Linux TCP server系列(6)-select模式下的多线程server
- Linux TCP server系列(5)-select模式下的单进程server
- Linux TCP server系列(6)-select模式下的多线程server
- TDiocpCoderTcpServer返回数据记录有条数限制的问题
- Head First设计模式C++实现--第二章:观察者(Oserver)模式
- 跨平台C++服务器程序开发 (4)tcp socket状态图(server端)
- Android网络编程之TCP/IP的Socket、ServerSocket模式
- 使用组合模式实现公司结构管理 C++
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之基础篇
- TDiocpCoderTcpServer 使用
- Android网络编程之TCP/IP的Socket、ServerSocket模式