SOCKET编程之 完成端口模型

完成端口模型据说是非常复杂的,但是核心是对集合数据结构的使用,以及某些顺序一定要保持好,其他的什么可扩展型,稳定性你可以通过一些编程技巧去实现。

// CompletionPort.cpp : Defines the entry point for the console application.
//
// write by larry
// 2009-8-20
// This is a server using completion port.

#include "stdafx.h"
#include <WINSOCK2.H>
#include <stdio.h>

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

#define PORT  5150
#define MSGSIZE  1024

typedef enum
{
    RECV_POSTED
} OPERATION_TYPE;

typedef struct 
{
    WSAOVERLAPPED  overlap;
    WSABUF         Buffer;
    char           szMessage[MSGSIZE];
    DWORD          NumberOfBytesRecvd;
    DWORD          Flags;
    OPERATION_TYPE OperationType;
} PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;

DWORD WINAPI WorkerThread(LPVOID CompletionPortID);


int main(int argc, char* argv[])
{
    WSADATA wsaData;
    SOCKET sListen, sClient;
    SOCKADDR_IN local, client;
    DWORD i, dwThreadId;
    int iAddrSize = sizeof(SOCKADDR_IN);
    HANDLE CompletionPort = INVALID_HANDLE_VALUE;
    SYSTEM_INFO sysinfo;
    LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
    // Initialize windows socket library
    WSAStartup(0x0202, &wsaData);
    // Create completion port
    CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    // Create worker thread
    GetSystemInfo(&sysinfo);
    for (i = 0; i < sysinfo.dwNumberOfProcessors; i++)
    {
        CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
    }
    // Create listening socket
    sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    // Bind
    local.sin_family = AF_INET;
    local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    local.sin_port = htons(PORT);
    bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN));
    // Listen
    listen(sListen, 3);
    while (TRUE)
    {
        // Accept a connection
        sClient = accept(sListen, (sockaddr*)&client, &iAddrSize);
        printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));        
        // Associate the newly arrived client socket with completion port
        CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)sClient, 0);
        // Launch an asynchronous operation for new arrived connection
        lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
            GetProcessHeap(),
            HEAP_ZERO_MEMORY,
            sizeof(PER_IO_OPERATION_DATA));
        lpPerIOData->Buffer.len = MSGSIZE;
        lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
        lpPerIOData->OperationType = RECV_POSTED;
        WSARecv(sClient,
            &lpPerIOData->Buffer,
            1,
            &lpPerIOData->NumberOfBytesRecvd,
            &lpPerIOData->Flags,
            &lpPerIOData->overlap,
            NULL);
    }

    PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL);
    CloseHandle(CompletionPort);
    closesocket(sListen);
    WSACleanup();
    return 0;
}

DWORD WINAPI WorkerThread(LPVOID CompletionPortID)
{
    HANDLE CompletionPort = (HANDLE)CompletionPortID;
    DWORD dwBytesTransferred;
    SOCKET sClient;
    LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
    while (TRUE)
    {
        GetQueuedCompletionStatus(
            CompletionPort,
            &dwBytesTransferred,
            (DWORD*)&sClient,
            (LPOVERLAPPED*)&lpPerIOData,
            INFINITE);
        if (dwBytesTransferred == 0xFFFFFFFF)
        {
            return 0;
        }
        if (lpPerIOData->OperationType == RECV_POSTED)
        {
            if (dwBytesTransferred == 0)
            {
                // Connection was closed by client
                closesocket(sClient);
                HeapFree(GetProcessHeap(), 0, lpPerIOData);
            }
            else
            {
                lpPerIOData->szMessage[dwBytesTransferred] = '\0';
                send(sClient, lpPerIOData->szMessage, dwBytesTransferred, 0);
                
                // Launch another asynchronous operation for sClient
                memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
                lpPerIOData->Buffer.len = MSGSIZE;
                lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
                lpPerIOData->OperationType = RECV_POSTED;
                WSARecv(sClient,
                    &lpPerIOData->Buffer,
                    1,
                    &lpPerIOData->NumberOfBytesRecvd,
                    &lpPerIOData->Flags,
                    &lpPerIOData->overlap,
                    NULL);
            }
        }
    }

    return 0;
}

 

posted @ 2013-07-03 15:16  和道一文字  阅读(547)  评论(0)    收藏  举报