// iocpServ.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
/**
*   iocpSerc.c
*/#include <stdio.h>
#include <windows.h>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")#define TCP_PORT 5150
#define DATA_BUFSIZE 8192typedef struct
{
    OVERLAPPED   Overlapped;
    WSABUF   DataBuffer;
    CHAR     Buffer[DATA_BUFSIZE];
    DWORD    BytesRecv;
    DWORD    BytesSend;
}PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA; typedef struct
 {
    SOCKET  Socket;
 }PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
 
 DWORD WINAPI ServerWorkerThread(LPVOID);
 
 void main(void)
 {
    WSADATA       wsaData;
    SOCKADDR_IN   InternetAddr;
    SOCKET        ListenSocket;
    SOCKET        AcceptSocket;
    LPPER_HANDLE_DATA        perHandleData;
    LPPER_IO_OPERATION_DATA    perIoData;
    HANDLE        CompletionPort;
 //   HANDLE        hThread;
    DWORD         RecvBytes;
    DWORD         ThreadId;
    SYSTEM_INFO   SystemInfo;
    DWORD         Ret;
    DWORD         Flags;
    int           i;
        //  加载winsock2.2
    Ret = WSAStartup(0x0202, &wsaData);
    //   Ret = WSAStartup(MAKEWORD(2,2), &wsaData)
    if(0 != Ret)
    {
        printf("WSAStartup failed with error%d\n", Ret);
        return;
    }
    
    //  创建一个完成端口
    CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if(NULL == CompletionPort)
    {
        printf("CreateIoCompletionPort() failed with error%d\n", GetLastError());
        return;
    }
    //  查看系统处理器个数
    GetSystemInfo(&SystemInfo);
    
    //  根据系统现有的处理器创建合理的线程数
    for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
    {
        HANDLE        hThread;
//  创建一个线程,把完成端口传递给它
        hThread = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort, 0, &ThreadId);
        if(NULL == hThread)
        {
            printf("CreateThread() failed with error%d\n", GetLastError());
            return;
        }
        //  关闭线程
        CloseHandle(hThread);
    }
    
    //  创建一个套接字
    ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    if(INVALID_SOCKET == ListenSocket)
    {
        printf("WSASocket() failed with error%d\n", WSAGetLastError());
        return;
    }
    
    InternetAddr.sin_family = AF_INET;
    InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    InternetAddr.sin_port = htons(TCP_PORT);
    
    //绑定套接字
    if(SOCKET_ERROR == bind(ListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)))
    {
        printf("bind() faile with error%d\n", WSAGetLastError());
        return;
    }
    
    //监听套接字
    if(SOCKET_ERROR == listen(ListenSocket, 5))
    {
        printf("listen() failed with error%d\n", WSAGetLastError());
        return;
    }
    
    // 接受socket,并把它与完成端口关联
    while(TRUE)
    {
        AcceptSocket = WSAAccept(ListenSocket, NULL, NULL, NULL, 0);
        if(SOCKET_ERROR == AcceptSocket)
        {
            printf("WSAAccept() failed with error%d\n", WSAGetLastError());
            return;
        }
        perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(LPPER_HANDLE_DATA));
        if(NULL == perHandleData)
        {
            printf("GlobalAlloc() failed with error %d\n", GetLastError());
            return;
        }        printf("Socket number %d connect\n", AcceptSocket);
        perHandleData->Socket = AcceptSocket;
        
        if(NULL == CreateIoCompletionPort((HANDLE)AcceptSocket, CompletionPort, (DWORD)perHandleData, 0))
        {
            printf("CreateIoCompletionPort() failed with error %d\n", GetLastError());
            return;
        }
        
        perIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof(LPPER_IO_OPERATION_DATA));
        if(NULL == perIoData)
        {
            printf("GlobalAlloc() failed with error %d\n", GetLastError());
            return;
        }
        
        ZeroMemory(&(perIoData->Overlapped), sizeof(OVERLAPPED));
        perIoData->BytesRecv = 0;
        perIoData->BytesSend = 0;
perIoData->DataBuffer.len = DATA_BUFSIZE;
        perIoData->DataBuffer.buf = perIoData->Buffer;
        
        
        Flags = 0;
        if(SOCKET_ERROR == WSARecv(AcceptSocket, &(perIoData->DataBuffer), 1, &(RecvBytes), &Flags, &(perIoData->Overlapped), NULL))
        {
            if(WSAGetLastError() != ERROR_IO_PENDING)
            {
                printf("WSARecv() failed with error %d\n", WSAGetLastError());
                return;
            }
        }
    }
 }
 
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
    HANDLE CompletionPort = (HANDLE)CompletionPortID;
    
    DWORD   BytesTransferred;
    LPOVERLAPPED   Overlapped;
    LPPER_IO_OPERATION_DATA   perIoData;
    LPPER_HANDLE_DATA      perHandleData;
    DWORD   SendBytes, RecyBytes;
    DWORD   Flags;
    
    while(TRUE)
    {
        if(GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&perHandleData, (LPOVERLAPPED *)&perIoData, INFINITE) == 0)
        {
            printf("GetQueuedCompletionStatus() failed with error %d\n", GetLastError());
            return 0;
        }        if(0 == BytesTransferred)
        {
            printf("Closing socket %d\n", perHandleData->Socket);
            if(SOCKET_ERROR == closesocket(perHandleData->Socket))
            {
                printf("closesocket() failed with error %d\n"), WSAGetLastError();
                return 0;
            }
            GlobalFree(perHandleData);
            GlobalFree(perIoData);
            continue;
        }
        
        if(0 == perIoData->BytesRecv)
        {
            perIoData->BytesRecv = BytesTransferred;
            perIoData->BytesSend = 0;
printf("BytesRecv:%s\n", perIoData->BytesRecv);
        }
        else
        {
            perIoData->BytesSend += BytesTransferred;
printf("BytesSend:%s\n", perIoData->BytesSend);
        }
        
        if(perIoData->BytesRecv > perIoData->BytesSend)
        {
            ZeroMemory(&(perIoData->Overlapped), sizeof(OVERLAPPED));
            
            perIoData->DataBuffer.buf = perIoData->Buffer + perIoData->BytesSend;
            perIoData->DataBuffer.len = perIoData->BytesRecv - perIoData->BytesSend;
            
            if(SOCKET_ERROR == WSASend(perHandleData->Socket, &(perIoData->DataBuffer), 1,
                &SendBytes, 0, &(perIoData->Overlapped), NULL))
            {
                if(ERROR_IO_PENDING != WSAGetLastError())
                {
                    printf("WSASend() failed with error %d\n", WSAGetLastError());
                    return 0;
                }
            }
        }
        else
        {
            perIoData->BytesRecv = 0;
            Flags = 0;
            ZeroMemory(&(perIoData->Overlapped), sizeof(OVERLAPPED));
            
            perIoData->DataBuffer.len = DATA_BUFSIZE;
            perIoData->DataBuffer.buf = perIoData->Buffer;            if(SOCKET_ERROR == WSARecv(perHandleData->Socket, &(perIoData->DataBuffer), 1,
                &RecyBytes, &Flags, &(perIoData->Overlapped), NULL))
            {
                if(ERROR_IO_PENDING != WSAGetLastError())
                {
                    printf("WSARecv() failed with error %d\n", WSAGetLastError());
                    return 0;
                }
            }
        }
    }
}
在上述红色处报有问题:
DataBufferf - buf 0x00040003 <错误的指针> char *
BytesRecv CXX0030: 错误: 无法计算表达式的值
BytesSend CXX0030: 错误: 无法计算表达式的值

解决方案 »

  1.   

    "perIoData= (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(LPPER_IO_OPERATION_DATA));"
    改成如下:
    perIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA));
      

  2.   

    谢谢,先前的错误去掉了。
    但在接下来又发生了个错误:
    iocpServ.exe 中的 0x10227c2f (msvcr80d.dll) 处未处理的异常: 0xC0000005: 读取位置 0x00000009 时发生访问冲突
    perIoData CXX0017: 错误: 没有找到符号“perIoData”,
    错误指向output.c文件。碰到内存、指针错误不知从何入手,有谁能提供点资料学习下吗?谢谢了!
      

  3.   

    堆栈跟踪显示这个:
    msvcr80d.dll!_output_l(_iobuf * stream=0x10310bf0, const char * format=0x0041684c, localeinfo_struct * plocinfo=0x00000000, char * argptr=0x0061fe88)  行1646 + 0x1f 字节msvcr80d.dll!printf(const char * format=0x00416840, ...)  行63 + 0x18 字节 iocpServ.exe!ServerWorkerThread(void * CompletionPortID=0x00000fc0)  行201 + 0x17 字节
      

  4.   

    参照我这个看看!
    http://blog.csdn.net/jasonM2008/archive/2009/08/13/4441514.aspx
      

  5.   

    Mark
    printf("BytesRecv:%s\n", perIoData->BytesRecv);
    printf("BytesRecv:%d\n", perIoData->BytesRecv);
    借用学习