IOCP 的SOCKET服务器,来自侯捷的多线程程序设计和CODEPROJECTS


IOCP (I/O Completion Ports),中文名"输入输出完成端口"。
为什么要使用IOCP:

1,如果一个客户端对应开启一个线程,对于系统资源是一种浪费,同时也是一项挑战;
2,线程是内核对象,内核的资源是有限的,PC的最大线程数大概在2000左右,同时开启线程也需要额外的系统开销,时间和效率上不划算。

优点:

1,没有HANDLS数量限制,与WaitForMultipleObjects()的优势点;
2,基于线程池,准许一个线程暂停,由另一线程为其服务;
3,支持scalable架构。

主要的工作有三个:

1,关联一个SOCKET到IOCP

IOCP的创建函数有两个用途:
HANDLE CreateIoCompletionPort (
HANDLE
FileHandle, // file handle to associate with // the I/O completion port
HANDLE ExistingCompletionPort, // handle to the I/O completion port
DWORD
CompletionKey, // per-file completion key for I/O // completion packets
DWORD
NumberOfConcurrentThreads // number of threads allowed to // execute concurrently);

举例:
CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, g_h.nThreadNum);//方式一:用于创建一个IOCP;

HANDLE h = CreateIoCompletionPort((HANDLE) socket, 
             hCompletionPort, dwCompletionKey, m_nIOWorkers);
//方式二,用于关联一个异步IO对象到IOCP,同时制定CompletionKey参数,和工作线程数量。

注意:第一个参数HANDLE在创建时需要在CreateFile()中制定FILE_FLAG_OVERLAPPED标志。

2,IO的异步调用

BOOL PostQueuedCompletionStatus(
 HANDLE
CompletionPort, // handle to an I/O completion port
 DWORD
dwNumberOfBytesTransferred, // value to return via // GetQueuedCompletionStatus' //lpNumberOfBytesTranferred
 DWORD
dwCompletionKey, // value to return via // GetQueuedCompletionStatus' //lpCompletionKey
 LPOVERLAPPED
lpOverlapped // value to return via // GetQueuedCompletionStatus'lpOverlapped);

3,线程的同步

BOOL GetQueuedCompletionStatus(
 HANDLE
CompletionPort, // the I/O completion port of interest
 LPDWORD
lpNumberOfBytesTransferred, // to receive number of bytes // transferred during I/O
 LPDWORD
lpCompletionKey, // to receive file's completion key
 LPOVERLAPPED
*lpOverlapped, // to receive pointer to OVERLAPPED // structure
 DWORD
dwMilliseconds // optional timeout value);

在SOCKET处理过程中,需要处理的4个棘手的问题:

  • The WSAENOBUFS error problem.
  • The package reordering problem.
  • The access violation problem.
  • Asynchronous pending reads and byte chunk package processing problem.


  • 工作步骤:

    1,产生一个IOCP;   使用 CreateIoCompletionPort 
    2,让产生的IOCP句柄和一个SOCKET句柄关联;  每关联一个HANDLE都使用 CreateIoCompletionPort 
    3,产生一堆线程; 线程的数量根据当前CPU的数量计算: 2 * CPU数量 + 2
    4,让每一个线程都在IOCP上等待; GetQueuedCompletionStatus
    5,对关联的SOCKET句柄发送overlapped IO请求。

    线程池中的所有线程个数 = 目前正在执行的线程 + 被阻塞的线程 + 在IOCP上等待的线程


    侯捷 多线程程序设计中 ECHO服务器举例:

    程序部分一:在主程序MAIN函数中,

    初始化SOCKET,在服务端口侦听;
    线程集的创建;
    IOCP的初始化,使用CreateIoCompletionPort 的方式一;

    在FOR循环体中,接受CLIENT的连接请求,为接受到的每个SOCKET CLIENT绑定IOCP,CreateIoCompletionPort 的方式二;
               在绑定每一个CLIENT到IOCP时,需要传递一个DWORD CompletionKey,  该参数为CLIENT信息的一个指针。
               DWORD ContentKey* pKey;

    程序部分二:在线程函数中,

    FOR循环体中,不断查询IO队列的状态:    GetQueuedCompletionStatus

    根据获取到的CLIENT状态进行相应处理。

    关键的信息就是ContentKey,每一个CLIENT都有一个。

    The access violation problem.
    • The access violation problem.

    你可能感兴趣的:(多线程,socket,File,服务器,processing,Access)