winsock IOCP收发例子

转载 2013年12月05日 19:39:43
// IOCP_console3.cpp: 主项目文件。
#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#include <MSWSock.h>
#include <Windows.h>
#include <process.h>
#pragma comment(lib, "WS2_32.lib")

#define MAX_BUFFER	256
#define MAX_TIMEOUT 1000
#define MAX_SOCKET  1024
#define MAX_THREAD	64
#define MAX_ACCEPT  5

typedef enum _OPERATION_INFO_
{
  OP_NULL,
  OP_ACCEPT,
  OP_READ,
  OP_WRITE
}OPERATIONINFO;

typedef struct _PER_HANDLE_DATA_
{
public:
  _PER_HANDLE_DATA_()
  {
    clean();
  }
  ~_PER_HANDLE_DATA_()
  {
    clean();
  }
protected:
  void clean()
  {
    sock = INVALID_SOCKET;
    memset(&addr, 0, sizeof(addr));
    addr.sin_addr.S_un.S_addr = INADDR_ANY;
    addr.sin_port = htons(0);
    addr.sin_family = AF_INET;
  }
public:	
  SOCKET sock;
  SOCKADDR_IN addr;
}PERHANDLEDATA, *PPERHANDLEDATA;

typedef struct _PER_IO_DTATA_
{
public: 
  _PER_IO_DTATA_()
  {
    clean();
  }
  ~_PER_IO_DTATA_()
  {
    clean();
  }
  void clean()
  {
    ZeroMemory(&ol, sizeof(ol));
    memset(buf, 0, sizeof(buf));
    sAccept = INVALID_SOCKET;
    sListen = INVALID_SOCKET;
    wsaBuf.buf = buf;
    wsaBuf.len = MAX_BUFFER;
    opType =  OP_NULL;
  }
public:
  WSAOVERLAPPED ol;
  SOCKET sAccept; // Only valid with AcceptEx
  SOCKET sListen; // Only valid with AcceptEx
  WSABUF wsaBuf;
  char buf[MAX_BUFFER];
  OPERATIONINFO opType;
}PERIODATA, *PPERIODATA;

HANDLE hThread[MAX_THREAD] = {0};
PERIODATA* pAcceptData[MAX_ACCEPT] = {0};
int g_nThread = 0;
BOOL g_bExitThread = FALSE;
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockAddrs = NULL;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;

unsigned __stdcall ThreadProc(LPVOID lParam);
BOOL PostAccept(PERIODATA* pIoData);

int main(int argc, TCHAR* argv[])
{
  WORD wVersionRequested = MAKEWORD(2, 2);
  WSADATA wsaData;
  if(0 != WSAStartup(wVersionRequested, &wsaData))
  {
    printf("WSAStartup failed with error code: %d\n", GetLastError());
    return EXIT_FAILURE;
  }

  if(2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion))
  {
    printf("Socket version not supported.\n");
    WSACleanup();
    return EXIT_FAILURE;
  }

  // Create IOCP
  HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
  if(NULL == hIOCP)
  {
    printf("CreateIoCompletionPort failed with error code: %d\n", WSAGetLastError());
    WSACleanup();
    return EXIT_FAILURE;
  }

  // Create worker thread
  SYSTEM_INFO si = {0};
  GetSystemInfo(&si);
  for(int i = 0; i < 1; i++)
  {
    hThread[g_nThread] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, (LPVOID)hIOCP, 0, NULL);
    if(NULL == hThread[g_nThread])
    {
      printf("_beginthreadex failed with error code: %d\n", GetLastError());
      continue;
    }
    ++g_nThread;

    if(g_nThread > MAX_THREAD)
    {
      break;
    }
  }

  // Create listen SOCKET
  SOCKET sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  if(INVALID_SOCKET == sListen)
  {
    printf("WSASocket failed with error code: %d\n", WSAGetLastError());
    goto EXIT_CODE;
  }

  // Associate SOCKET with IOCP
  if(NULL == CreateIoCompletionPort((HANDLE)sListen, hIOCP, NULL, 0))
  {
    printf("CreateIoCompletionPort failed with error code: %d\n", WSAGetLastError());
    if(INVALID_SOCKET != sListen)
    {
      closesocket(sListen);
      sListen = INVALID_SOCKET;
    }
    goto EXIT_CODE;
  }

  // Bind SOCKET
  SOCKADDR_IN addr;
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
  addr.sin_port = htons(6677);
  if(SOCKET_ERROR == bind(sListen, (LPSOCKADDR)&addr, sizeof(addr)))
  {
    printf("bind failed with error code: %d\n", WSAGetLastError());
    if(INVALID_SOCKET != sListen)
    {
      closesocket(sListen);
      sListen = INVALID_SOCKET;
    }
    goto EXIT_CODE;
  }

  // Start Listen
  if(SOCKET_ERROR == listen(sListen, 200))
  {
    printf("listen failed with error code: %d\n", WSAGetLastError());
    if(INVALID_SOCKET != sListen)
    {
      closesocket(sListen);
      sListen = INVALID_SOCKET;
    }
    goto EXIT_CODE;
  }

  printf("Server start, wait for client to connect ...\n");

  DWORD dwBytes = 0;
  if(SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx,
    sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL))
  {
    printf("WSAIoctl failed with error code: %d\n", WSAGetLastError());
    if(INVALID_SOCKET != sListen)
    {
      closesocket(sListen);
      sListen = INVALID_SOCKET;
    }
    goto EXIT_CODE;
  }

  if(SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockAddrs, 
    sizeof(GuidGetAcceptExSockAddrs), &lpfnGetAcceptExSockAddrs, sizeof(lpfnGetAcceptExSockAddrs), 
    &dwBytes, NULL, NULL))
  {
    printf("WSAIoctl failed with error code: %d\n", WSAGetLastError());
    if(INVALID_SOCKET != sListen)
    {
      closesocket(sListen);
      sListen = INVALID_SOCKET;
    }
    goto EXIT_CODE;
  }

  // Post MAX_ACCEPT accept
  for(int i=0; i<MAX_ACCEPT; i++)
  {
    pAcceptData[i] = new PERIODATA;
    pAcceptData[i]->sListen = sListen;
    PostAccept(pAcceptData[i]);
  }
  // After 1 hour later, Server shutdown.
  Sleep(1000 * 60 *60);

EXIT_CODE:
  g_bExitThread = TRUE;

  PostQueuedCompletionStatus(hIOCP, 0, NULL, NULL);
  WaitForMultipleObjects(g_nThread, hThread, TRUE, INFINITE);
  for(int i = 0; i < g_nThread; i++)
  {
    CloseHandle(hThread[g_nThread]);
  }

  for(int i=0; i<MAX_ACCEPT; i++)
  {
    if(pAcceptData[i])
    {
      delete pAcceptData[i];
      pAcceptData[i] = NULL;
    }
  }

  if(INVALID_SOCKET != sListen)
  {
    closesocket(sListen);
    sListen = INVALID_SOCKET;
  }
  CloseHandle(hIOCP); // Close IOCP

  WSACleanup();
  return 0;
}

BOOL PostAccept(PERIODATA* pIoData)
{
  if(INVALID_SOCKET == pIoData->sListen)
  {
    return FALSE;
  }

  DWORD dwBytes = 0;
  pIoData->opType = OP_ACCEPT;
  pIoData->sAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  if(INVALID_SOCKET == pIoData->sAccept)
  {
    printf("WSASocket failed with error code: %d\n", WSAGetLastError());
    return FALSE;
  }

  if(FALSE == lpfnAcceptEx(pIoData->sListen, pIoData->sAccept, pIoData->wsaBuf.buf, pIoData->wsaBuf.len - ((sizeof(SOCKADDR_IN)+16)*2), 
    sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &dwBytes, &(pIoData->ol)))
  {
    if(WSA_IO_PENDING != WSAGetLastError())
    {
      printf("lpfnAcceptEx failed with error code: %d\n", WSAGetLastError());

      return FALSE;
    }
  }
  return TRUE;
}

unsigned __stdcall ThreadProc(LPVOID lParam)
{
  HANDLE hIOCP = (HANDLE)lParam;

  PERHANDLEDATA* pPerHandleData = NULL;
  PERIODATA* pPerIoData = NULL;
  WSAOVERLAPPED* lpOverlapped = NULL;
  DWORD dwTrans = 0;
  DWORD dwFlags = 0;
  while(!g_bExitThread)
  {
    BOOL bRet = GetQueuedCompletionStatus(hIOCP, &dwTrans, (PULONG_PTR)&pPerHandleData, &lpOverlapped, INFINITE);
    if(!bRet)
    {
      // Timeout and exit thread
      if(WAIT_TIMEOUT == GetLastError())
      {
        continue;
      }
      // Error
      printf("GetQueuedCompletionStatus failed with error: %d\n", GetLastError());
      continue;
    }
    else
    {
      pPerIoData = CONTAINING_RECORD(lpOverlapped, PERIODATA, ol);
      if(NULL == pPerIoData)
      {
        // Exit thread
        break;
      }

      if((0 == dwTrans) && (OP_READ == pPerIoData->opType || OP_WRITE == pPerIoData->opType))
      {
        // Client leave.
        printf("Client: <%s : %d> leave.\n", inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port));
        closesocket(pPerHandleData->sock);
        delete pPerHandleData;
        delete pPerIoData;
        continue;
      }
      else
      {
        switch(pPerIoData->opType)
        {
        case OP_ACCEPT: // Accept
          {	
            SOCKADDR_IN* remote = NULL;
            SOCKADDR_IN* local = NULL;
            int remoteLen = sizeof(SOCKADDR_IN);
            int localLen = sizeof(SOCKADDR_IN);
            lpfnGetAcceptExSockAddrs(pPerIoData->wsaBuf.buf, pPerIoData->wsaBuf.len - ((sizeof(SOCKADDR_IN)+16)*2),
              sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, (LPSOCKADDR*)&local, &localLen, (LPSOCKADDR*)&remote, &remoteLen);
            printf("Client <%s : %d> come in.\n", inet_ntoa(remote->sin_addr), ntohs(remote->sin_port));
            printf("Recv Data: <%s : %d> %s.\n", inet_ntoa(remote->sin_addr), ntohs(remote->sin_port), pPerIoData->wsaBuf.buf);

            if(NULL != pPerHandleData)
            {
              delete pPerHandleData;
              pPerHandleData = NULL;
            }
            pPerHandleData = new PERHANDLEDATA;
            pPerHandleData->sock = pPerIoData->sAccept;

            PERHANDLEDATA* pPerHandle = new PERHANDLEDATA;
            pPerHandle->sock = pPerIoData->sAccept;
            PERIODATA* pPerIo = new PERIODATA;
            pPerIo->opType = OP_WRITE;
            strcpy_s(pPerIo->buf, MAX_BUFFER, pPerIoData->buf);
            DWORD dwTrans = strlen(pPerIo->buf);
            memcpy(&(pPerHandleData->addr), remote, sizeof(SOCKADDR_IN));
            // Associate with IOCP
            if(NULL == CreateIoCompletionPort((HANDLE)(pPerHandleData->sock), hIOCP, (ULONG_PTR)pPerHandleData, 0))
            {
              printf("CreateIoCompletionPort failed with error code: %d/n", GetLastError());
              closesocket(pPerHandleData->sock);
              delete pPerHandleData;
              continue;
            }

            // Post Accept
            memset(&(pPerIoData->ol), 0, sizeof(pPerIoData->ol));
            PostAccept(pPerIoData);

            // Post Receive						
            DWORD dwFlags = 0;
            if(SOCKET_ERROR == WSASend(pPerHandle->sock, &(pPerIo->wsaBuf), 1, 
              &dwTrans, dwFlags, &(pPerIo->ol), NULL))
            {
              if(WSA_IO_PENDING != WSAGetLastError())
              {
                printf("WSASend failed with error code: %d\n", WSAGetLastError());
                closesocket(pPerHandle->sock);
                delete pPerHandle;
                delete pPerIo;
                continue;
              }
            }
          }
          break;

        case OP_READ: // Read
          printf("recv client <%s : %d> data: %s\n", inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port), pPerIoData->buf);
          pPerIoData->opType = OP_WRITE;
          memset(&(pPerIoData->ol), 0, sizeof(pPerIoData->ol));
          if(SOCKET_ERROR == WSASend(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, dwFlags, &(pPerIoData->ol), NULL))
          {
            if(WSA_IO_PENDING != WSAGetLastError())
            {
              printf("WSASend failed with error code: %d.\n", WSAGetLastError());
              continue;
            }
          }
          break;

        case OP_WRITE: // Write
          {
            pPerIoData->opType = OP_READ;
            dwFlags = 0;
            memset(&(pPerIoData->ol), 0, sizeof(pPerIoData->ol));
            memset(pPerIoData->buf, 0, sizeof(pPerIoData->buf));
            pPerIoData->wsaBuf.buf = pPerIoData->buf;
            dwTrans = pPerIoData->wsaBuf.len = MAX_BUFFER;
            if(SOCKET_ERROR == WSARecv(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, &dwFlags, &(pPerIoData->ol), NULL))
            {
              if(WSA_IO_PENDING != WSAGetLastError())
              {
                printf("WSARecv failed with error code: %d.\n", WSAGetLastError());
                continue;
              }
            }
          }
          break;

        default:
          break;
        }
      }
    }
  }
  return 0;
}

windows下简单的IOCP模型迭代回声服务器实例

#include #include #include #include #pragma comment(lib,"ws2_32.lib") #define BUF_SIZE 100 #define R...
  • zl908760230
  • zl908760230
  • 2017年04月25日 16:04
  • 476

Winsock IO模型之IOCP模型

Windows平台上伸缩性最好的一种I/O模型莫过IOCP了,不过设计和实现起来比较复杂一些。针对成千上万个套接字的并发处理,IOCP采用了线程池+队列+重叠结构的内核机制完成任务。需要说明的是IOC...
  • Lostyears
  • Lostyears
  • 2012年05月08日 21:02
  • 19623

在WinSock上使用IOCP

 在WinSock上使用IOCP 本文章假设你已经理解WindowsNT的I/O模型以及I/O完成端口(IOCP),并且比较熟悉将要用到的API,如果你打算学习IOCP,请参考Jeffery Rich...
  • wildwolf113
  • wildwolf113
  • 2007年04月26日 09:37
  • 943

Winsock IOCP模型(二) (转)

// IOCP2.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include...
  • dragoo1
  • dragoo1
  • 2016年08月30日 21:56
  • 530

WinSock编程流程(2)- UDP

TCP 由于可靠、稳定的特点而被用在大部分场合,但它对系统资源要求比较高。UDP 是一个简单的面向数据报的传输层协议,又叫用户数据报协议。它提供了无连接的、不可靠的数据传输服务。无连接是指它不像TCP...
  • u011628751
  • u011628751
  • 2015年06月10日 14:57
  • 876

IOCP完整例子

本文是我在学习IOCP的时候,第一次写一个完整的例子出来,当然了,参考了CSDN上一些朋友的博客,大部分都是按照他们的思路写的,毕竟我是初学者,参考现成的学起来比较快。当然了,真正用到项目中的IOCP...
  • zhujunxxxxx
  • zhujunxxxxx
  • 2014年02月28日 09:58
  • 2300

IOCP 浅析与实例

这一年半来一直在做游戏项目逻辑层,学会了不少东西,觉得自己应该看看服务器底层的东西了,主要的东西就是网络模块,网络模块是沿用以前项目的,在 我们项目中被我们头改动过几次,现在还是比较稳定的。因为是Wi...
  • liujiayu2
  • liujiayu2
  • 2015年06月10日 19:15
  • 597

用完成端口(iocp) 写的一个简单的服务端例子

下面是用完成端口写的一个简单的 例子, 完成端口和重叠io 一样都是异步io。 代码如下。欢迎大家建议 改进、...
  • billiejeannotmylover
  • billiejeannotmylover
  • 2014年01月11日 00:54
  • 1424

简单的IOCP例子

使用IOCP模型编程的优点  ① 帮助维持重复使用的内存池。(与重叠I/O技术有关)  ② 去除删除线程创建/终结负担。  ③ 利于管理,分配线程,控制并发,最小化的线程上下文切换。  ④ 优...
  • hkwlg1314
  • hkwlg1314
  • 2015年10月29日 17:01
  • 188

完成端口IOCP,重叠,消息选择,消息异步等等....

谢谢 免杀之神给的PEB过防火墙的资料, 时间不多看群里热闹把 讨论的是关于 多连接的问题记下来以后整理.........  夕草(8999094) 2007-11-29 22:26:20我夕草(89...
  • chinafe
  • chinafe
  • 2007年11月30日 14:41
  • 1727
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:winsock IOCP收发例子
举报原因:
原因补充:

(最多只允许输入30个字)