您的位置:首页 > 理论基础 > 计算机网络

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;
}


服务端

客户端
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iocp handle socket