C语言IOCP

C语言的IOCP example

#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

#define   Port				5000   
#define   Max_Buffer_Size   4096   
#define   Max_Threads		2

static GUID ax_guid = WSAID_ACCEPTEX;
static GUID as_guid = WSAID_GETACCEPTEXSOCKADDRS;

const char res_bufs[] = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\nWelcome to Server.";


LPFN_ACCEPTEX              lpfn_AcceptEx;
LPFN_GETACCEPTEXSOCKADDRS  lpfn_GetAcceptExSockAddrs;

HANDLE						iocp;
SOCKET                      listener;


typedef struct
{
	OVERLAPPED		overlapped;
	SOCKET			accept;
	WSABUF			wsa_buf;
	CHAR			buf[Max_Buffer_Size];
	DWORD			bytes_send;
	DWORD			bytes_recv;
	int				action;

} Pre_IO_Context, *LP_Pre_IO_Context;


int init(void);

DWORD WINAPI worker_thread(LPVOID iocp);

int post_accept_ex();
int post_recv(Pre_IO_Context* io_ctx);
int post_send(Pre_IO_Context* io_ctx);

int do_accept(HANDLE iocp, Pre_IO_Context* io_ctx);
int do_recv(Pre_IO_Context* io_ctx);
int do_send(Pre_IO_Context* io_ctx);


int main(void) 
{
	int						i;
	DWORD					thread_id;
	HANDLE                  threads[Max_Threads];
	LINGER					linger;
	SOCKADDR_IN				inet_addr;

	int opt_val = 1;
	int opt_len = sizeof(int);


	printf("Win IOCP");

	
	if (-1 == init()) 
	{
		printf("init failed.");
		return -1;
	}


	if ((iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
	{
		printf("CreateIoCompletionPort Failed,err: %d\n", GetLastError());
		return -1;
	}

	for (i = 0; i < Max_Threads; i++)
	{
		if ((threads[i] = CreateThread(NULL, 0, worker_thread, iocp, 0, &thread_id)) == NULL)
		{
			printf("CreateThread() failed. error: %d\n", GetLastError());
			CloseHandle(iocp);
			WSACleanup();
			return -1;
		}
	}


	if ((listener = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
	{
		printf("WSASocket() failed. error: %d\n", WSAGetLastError());
		WSACleanup();
		return -1;
	}

	if (-1 == setsockopt(listener, SOL_SOCKET, SO_KEEPALIVE, (const void*)& opt_val, opt_len))
	{
		printf("setsockopt(SO_KEEPALIVE) failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}

	// closesocket: return immediately and send RST
	linger.l_onoff = 1;
	linger.l_linger = 0;
	if (-1 == setsockopt(listener, SOL_SOCKET, SO_LINGER, (char*)& linger, sizeof(linger)))
	{
		printf("setsockopt(SO_LINGER) failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}

	// Windows only support SO_REUSEADDR
	if (-1 == setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const void*)& opt_val, opt_len))
	{
		printf("setsockopt(SO_REUSEADDR) failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}



	if (INVALID_HANDLE_VALUE == CreateIoCompletionPort((HANDLE)listener, iocp, 0, 0))
	{
		printf("CreateIoCompletionPort(listener) failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}


	printf("Associate socket with iocp. socket: %I64d, iocp: %p \n", listener, iocp);


	inet_addr.sin_family = AF_INET;
	inet_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	inet_addr.sin_port = htons(Port);
	if (SOCKET_ERROR == bind(listener, (PSOCKADDR)& inet_addr, sizeof(inet_addr)))
	{
		printf("bind() failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}

	
	if (SOCKET_ERROR == listen(listener, SOMAXCONN))
	{
		printf("listen() failed.");
		closesocket(listener);
		WSACleanup();
		CloseHandle(iocp);
		return -1;
	}


	printf("Listen on prot(%d).\n", Port);


	for (i = 0; i < Max_Threads; i++)
	{
		post_accept_ex();
	}


	// MAXIMUM_WAIT_OBJECTS
	WaitForMultipleObjects(Max_Threads, threads, FALSE, INFINITE);

	//PostQueuedCompletionStatus(iocp, 0, (DWORD)-1, NULL);

	printf("All threads exit.");

	return 0;
}


int init(void) 
{
	SYSTEM_INFO		sys_info;	
	WSADATA			wsa_data;

	DWORD			ret;
	SOCKET          s;
	

	GetSystemInfo(&sys_info);

	printf("System memery page size: %d \n", sys_info.dwPageSize);
	printf("System cpus: %d \n", sys_info.dwNumberOfProcessors);


	if ((ret = WSAStartup(0x0202, &wsa_data)) != 0)
	{
		printf("WSAStartup() failed. error: %d\n", ret);
		return -1;
	}

	if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
	{
		printf("Require Windows Socket Version 2.2 Error!\n");
		WSACleanup();
		return -1;
	}


	s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (s == -1) {
		printf("socket() failed.");
		return -1;
	}


	if (-1 == WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &ax_guid, sizeof(GUID),
		&lpfn_AcceptEx, sizeof(LPFN_ACCEPTEX), &ret, NULL, NULL))
	{
		printf("WSAIoctl(LPFN_ACCEPTEX) failed.");
		return -1;
	}

	if (-1 == WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &as_guid, sizeof(GUID),
		&lpfn_GetAcceptExSockAddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS),
		&ret, NULL, NULL))
	{
		printf("WSAIoctl(LPFN_GETACCEPTEXSOCKADDRS) failed.");
		return -1;
	}
	

	if (-1 == closesocket(s)) {
		printf("closesocket() failed.");
		return -1;
	}

	return 0;
}


DWORD WINAPI worker_thread(LPVOID lp_iocp) 
{
	DWORD				bytes;
	LP_Pre_IO_Context	io_ctx;
	
	DWORD				err_no = 0;
	HANDLE				iocp = (HANDLE)lp_iocp;
	PULONG_PTR			lp_completion_key = NULL;


	while (TRUE)
	{
		if (0 == GetQueuedCompletionStatus(iocp, &bytes, (PULONG_PTR)& lp_completion_key, (LPOVERLAPPED*)& io_ctx, INFINITE)) 
		{
			err_no = GetLastError();

			if (err_no) {

				if (WAIT_TIMEOUT == err_no) continue;

				if (ERROR_NETNAME_DELETED == err_no || ERROR_OPERATION_ABORTED == err_no)
				{
					printf("The socket was closed. error: %d\n", err_no);
					GlobalFree(io_ctx);

					continue;
				}

				printf("GetQueuedCompletionStatus() failed. error: %d\n", err_no);
				GlobalFree(io_ctx);

				return err_no;
			}
		}

		printf("GetQueuedCompletionStatus ---------------------------\n");


		if (NULL == io_ctx) 
		{
			printf("GetQueuedCompletionStatus() returned no operation");
			continue;
		}

		printf("IO_Context: %p \n", io_ctx);
		printf("Bytes transferred: %d \n", bytes);
		printf("IO_Context->Action: %d\n", io_ctx->action);


		if (0 == bytes && 0 != io_ctx->action) 
		{
			printf("No bytes transferred for the action.");
			GlobalFree(io_ctx);
			continue;
		}

		switch (io_ctx->action)
		{
		case 0:
			post_accept_ex();
			do_accept(iocp, io_ctx);
			post_recv(io_ctx);
			break;

		case 1:
			do_recv(io_ctx);
			post_send(io_ctx);
			break;

		case 2:
			do_send(io_ctx);
			break;

		default:
			printf("ERROR: No action match! \n");
			break;
		}
	}
}


int post_accept_ex()
{	
	LP_Pre_IO_Context		io_ctx;

	printf("post_accept_ex. listner: %I64d\n", listener);


	if ((io_ctx = (LP_Pre_IO_Context)GlobalAlloc(GPTR, sizeof(Pre_IO_Context))) == NULL)
	{
		printf("GlobalAlloc() failed. error: %d\n", GetLastError());
		return -1;
	}

	ZeroMemory(&(io_ctx->overlapped), sizeof(OVERLAPPED));	
	io_ctx->bytes_recv = 0;
	io_ctx->bytes_send = 0;
	io_ctx->wsa_buf.len = Max_Buffer_Size;
	io_ctx->wsa_buf.buf = io_ctx->buf;
	io_ctx->action = 0;

	io_ctx->accept = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (INVALID_SOCKET == io_ctx->accept) 
	{
		printf("WSASocketW() failed.\n");
		return -1;
	}


	if (0 == lpfn_AcceptEx(
		listener,

		io_ctx->accept,
		io_ctx->wsa_buf.buf,
		//io_ctx->wsa_buf.len - (sizeof(SOCKADDR_IN) + 16) * 2,
		0,

		sizeof(SOCKADDR_IN) + 16,
		sizeof(SOCKADDR_IN) + 16,

		&(io_ctx->bytes_recv),
		&(io_ctx->overlapped)
	)) {
		if (WSA_IO_PENDING != WSAGetLastError()) 
		{
			printf("LPFN_ACCEPTEX() failed. last error: %d\n", WSAGetLastError());
			return -1;
		}
	}

	printf("post_accept_ex. listner: %I64d, io_ctx: %p \n", listener, io_ctx);

	return 0;
}


int do_accept(HANDLE iocp, Pre_IO_Context* io_ctx) 
{
	printf("do_accept. io_ctx: %p \n", io_ctx);

	SOCKADDR_IN* local_sock_addr = NULL;
	SOCKADDR_IN* remote_sock_addr = NULL;
	int addr_len = sizeof(SOCKADDR_IN);
		
	if (-1 == setsockopt(io_ctx->accept, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)& listener, sizeof(SOCKET)))
	{
		printf("setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed. error: %d\n", WSAGetLastError());
	}


	lpfn_GetAcceptExSockAddrs(
		io_ctx->wsa_buf.buf,
		io_ctx->wsa_buf.len - ((addr_len + 16) * 2),
		addr_len + 16,
		addr_len + 16,
		(SOCKADDR * *)& local_sock_addr, &addr_len,
		(SOCKADDR * *)& remote_sock_addr, &addr_len
	);

	printf("do_accept, client socket: %I64d \n", io_ctx->accept);
	

	if (NULL == CreateIoCompletionPort((HANDLE)io_ctx->accept, iocp, 0, 0))
	{
		printf("CreateIoCompletionPort() failed. error: %d\n", GetLastError());
		return -1;
	}

	return 0;
}


int post_recv(Pre_IO_Context* io_ctx)
{
	printf("post_recv. io_ctx: %p \n", io_ctx);

	DWORD flags = 0;
	DWORD bytes = 0;
	DWORD err_no;
	int ret;

	ZeroMemory(&(io_ctx->overlapped), sizeof(OVERLAPPED));
	io_ctx->bytes_recv = 0;
	io_ctx->bytes_send = 0;
	io_ctx->wsa_buf.len = Max_Buffer_Size;
	io_ctx->wsa_buf.buf = io_ctx->buf;
	io_ctx->action = 1;

	ret = WSARecv(io_ctx->accept, &(io_ctx->wsa_buf), 1, &bytes, &flags, &(io_ctx->overlapped), NULL);

	err_no = WSAGetLastError();
	if (-1 == ret && WSA_IO_PENDING != err_no) 
	{
		if (err_no == WSAEWOULDBLOCK) printf("WSARecv() not ready");

		printf("WSARecv() faild. client socket: %I64d, error: %d\n", io_ctx->accept, err_no);

		return -1;
	}
	
	return 0;
}


int do_recv(Pre_IO_Context* io_ctx) 
{
	printf("do_recv. io_ctx: %p \n", io_ctx);
	printf("do_recv: recv data:\n %s \n", io_ctx->wsa_buf.buf);

	ZeroMemory(&(io_ctx->overlapped), sizeof(OVERLAPPED));
	io_ctx->bytes_recv = 0;
	io_ctx->bytes_send = 0;
	io_ctx->wsa_buf.len = Max_Buffer_Size;
	io_ctx->wsa_buf.buf = io_ctx->buf;
	io_ctx->action = 10;

	return 0;
}


int post_send(Pre_IO_Context* io_ctx)
{
	printf("post_send. io_ctx: %p \n", io_ctx);

	DWORD flags = 0;
	DWORD bytes = 0;
	DWORD err_no;
	int ret;


	io_ctx->wsa_buf.buf = &res_bufs;
	io_ctx->wsa_buf.len = sizeof(res_bufs) - 1;

	//io_ctx->overlapped.hEvent = WSACreateEvent();
	io_ctx->action = 2;


	ret = WSASend(io_ctx->accept, &(io_ctx->wsa_buf), 1, &bytes, 0, &(io_ctx->overlapped), NULL);
	err_no = WSAGetLastError();
	
	if (-1 == ret && err_no != WSA_IO_PENDING)
	{
		printf("WSASend() faild. error: %d\n", err_no);

		//WSAResetEvent(io_ctx->overlapped.hEvent);
		return -1;
	}

	if (err_no == WSA_IO_PENDING) 
	{
		printf("WSASend() posted. bytest: %d err: %d\n", bytes, err_no);
	}

	printf("WSASend send bytest: %d \n", bytes);

	/*
	WSAWaitForMultipleEvents(1, &io_ctx->overlapped.hEvent, TRUE, INFINITE, TRUE);
	printf("WSAWaitForMultipleEvents() failed. err: %d\n", WSAGetLastError());

	WSAGetOverlappedResult(io_ctx->accept, &io_ctx->overlapped, &io_ctx->bytes_send, FALSE, &flags);
	printf("WSAGetOverlappedResult() send bytes: %d\n", io_ctx->bytes_send);

	WSAResetEvent(io_ctx->overlapped.hEvent);
	printf("WSAResetEvent() err: %d\n", WSAGetLastError());
	*/

	return 0;
}


int do_send(Pre_IO_Context* io_ctx) 
{
	printf("do_send. io_ctx: %p \n", io_ctx);

	shutdown(io_ctx->accept, SD_BOTH);
	GlobalFree(io_ctx);

	return 0;
}

  

仅记录一个简单的示例,没有严谨的处理。同时谅解一下代码风格。

转载于:https://www.cnblogs.com/view85/p/11497064.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
源码,有注释 // IOCPServer.h: interface for the CIOCPServer class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_IOCPSERVER_H__3BBFA68A_31AC_42BB_806B_0D858AF0A861__INCLUDED_) #define AFX_IOCPSERVER_H__3BBFA68A_31AC_42BB_806B_0D858AF0A861__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #pragma once #pragma comment(lib,"Ws2_32.lib") #pragma comment(lib,"Mswsock.lib") #include <winsock2.h> #include <Mswsock.h> #define BUFFER_SIZE 1024*4//I/O请求的缓冲区大小 #define MAX_THREAD 2 //I/O服务器线程数量 //缓冲区对象,它包含了在套接字上处理I/O操作的必要信息 struct CIOCPBuffer { WSAOVERLAPPED ol; SOCKET sClient; //AcceptEx接收的客户套接字 char *buff; //I/0操作使用的缓冲区 int nLen; //buff缓冲区(使用的)大小 ULONG nSequenceNumber;//此I/O的序列号 int nOperation; //操作类型 CIOCPBuffer *pNext; }; //per-Handle数据,它包含了一个套接字的信息 struct CIOCPContext { SOCKET s; //套接字句柄 SOCKADDR_IN addrLocal; //连接的本地地址 SOCKADDR_IN addrRemote;//连接的远程地址 BOOL bClosing; //套接字是否关闭 int nOutStandingRecv; //此套接字上抛出的重叠操作的数量 int nOutStandingSend; ULONG nReadSequence; //安排给接受的下一个序列号 ULONG nCurrentReadSequence;//当前要读的序列号 CIOCPBuffer *pOutOfOrderReads;//记录没有按顺序完成的读I/O CRITICAL_SECTION Lock; //保护这个结构 CIOCPContext *pNext; }; class CIOCPServer //处理线程 { public: CIOCPServer(void); ~CIOCPServer(void); //开始服务 BOOL Start(int nPort=4567,int nMaxConnections=2000, int nMaxFreeBuffers=200,int nMaxFreeContexts=100,int nInitialReads=4); //停止服务 void Shutdown(); //关闭一个连接和关闭所有连接 void CloseAConnection(CIOCPContext *pContext); void CloseAllConnection(); //取得当前的连接数量 ULONG GetCurrentConnection() { return m_nCurrentConnection; }; //向指定客户发送文本 BOOL SendText(CIOCPContext *pContext,char *pszText,int nLen); protected: //申请和释放缓冲区对象 CIOCPBuffer*AllocateBuffer(int nLen); void ReleaseBuffer(CIOCPBuffer *pBuffer); //申请和释放套接字上下文 CIOCPContext *AllocateContext(SOCKET s); void ReleaseContext(CIOCPContext *pContext); //释放空闲缓冲区对象列表和空闲上下文对象列表 void FreeBuffers(); void FreeContexts(); //向连接列表中添加一个连接 BOOL AddAConnection(CIOCPContext *pContext); //插入和移除未决的接受请求 BOOL InsertPendingAccept(CIOCPBuffer *pBuffer); BOOL RemovePendingAccept(CIOCPBuffer *pBuffer); //取得下一个要读取的 CIOCPBuffer *GetNextReadBuffer(CIOCPContext *pContext,CIOCPBuffer *pBuffer); //投递接受I/O,发送I/0,接受I/O BOOL PostAccept(CIOCPBuffer *pBuffer); BOOL PostSend(CIOCPContext *pContext,CIOCPBuffer *pBuffer); BOOL PostRecv(CIOCPContext *pContext,CIOCPBuffer *pBuffer); //事件通知函数 void HandleIO(DWORD dwKey,CIOCPBuffer *pBuffer,DWORD dwTrans,int nError); //建立一个新的连接 virtual void OnConnectionEstablished(CIOCPContext *pContext,CIOCPBuffer*); //一个连接关闭 virtual void OnConnectionClosing(CIOCPContext *pContext,CIOCPBuffer*); //在一个连接上发生错误 virtual void OnConnectionError(CIOCPContext *pContext,CIOCPBuffer*,int nError); //在一个连接上的读操作完成 virtual void OnReadCompleted(CIOCPContext *pContext,CIOCPBuffer*); //在一个连接上写操作完成 virtual void OnWriteCompleted(CIOCPContext *pContext,CIOCPBuffer*); protected: //记录空闲结构信息 CIOCPBuffer *m_pFreeBufferList; CIOCPContext *m_pFreeContextList; int m_nFreeBufferCount; int m_nFreeContextCount; CRITICAL_SECTION m_FreeBufferListLock; CRITICAL_SECTION m_FreeContextListLock; //记录抛出的Accept请求 CIOCPBuffer *m_pPendingAccepts; long m_nPendingAcceptCount; CRITICAL_SECTION m_PendingAcceptsLock; //记录连接列表 CIOCPContext *m_pConnectionList; int m_nCurrentConnection; CRITICAL_SECTION m_ConnectionListLock; //用于投递Accept请求 HANDLE m_hAcceptEvent; HANDLE m_hRepostEvent; LONG m_nRepostCount; //服务器监听端口 int m_nPort; int m_nInitialAccepts; int m_nInitialReads; int m_nMaxAccepts; int m_nMaxSends; int m_nMaxFreeBuffers; int m_nMaxFreeContexts; int m_nMaxConnections; //监听线程 HANDLE m_hListenThread; //完成端口句柄 HANDLE m_hCompletion; //监听套接字句柄 SOCKET m_sListen; //AcceptEx函数地址 LPFN_ACCEPTEX m_lpfnAcceptEx; //GetAcceptExSockaddrs函数地址 LPFN_GETACCEPTEXSOCKADDRS m_lpfnGetAcceptExSockaddrs; //用于通知监听线程退出 BOOL m_bShutDown; //记录服务是否启动 BOOL m_bServerStarted; private://线程函数 static DWORD WINAPI _ListenThreadProc(LPVOID lpParam); static DWORD WINAPI _WorkerThreadProc(LPVOID lpParam); }; #endif // !defined(AFX_IOCPSERVER_H__3BBFA68A_31AC_42BB_806B_0D858AF0A861__INCLUDED_)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值