完成端口例子

#include "stdafx.h"

#include <iostream.h>

#include

#include

#include

#define PORT 5150

#define DATA_BUFSIZE 8192

typedef struct

{

 OVERLAPPED OVerlapped;

 WSABUF DATABuf;

 CHAR Buffer[DATA_BUFSIZE];

 DWORD BytesSend,BytesRecv;

}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;

typedef struct

 {

 SOCKET Socket;

}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID);

int main(int argc, char* argv[])

{

       SOCKADDR_IN InternetAddr;

 SOCKET Listen,Accept;

 HANDLE CompetionPort;

 SYSTEM_INFO SystenInfo;

 LPPER_HANDLE_DATA PerHandleData;

 LPPER_IO_OPERATION_DATA PerIOData;

 int i;

 DWORD RecvBytes;

 DWORD Flags;

 DWORD ThreadID;

 WSADATA wsadata;

 DWORD Ret;

 

 if (Ret = WSAStartup(0x2020,&wsadata) != 0)

 {

    printf("WSAStartup failed with error %d"n",Ret);

    return 0;

 }

   //打开一个空的完成端口

 if ((CompetionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0)) == NULL)

 {

    printf("CreateIoCompletionPort failed with error %d"n",GetLastError());

    return 0;

 }

 

 GetSystemInfo(&SystenInfo);

  

 // 开启cpu个数的2倍个的线程

 for (i=0; i < SystenInfo.dwNumberOfProcessors*2; i++)

 {

    HANDLE ThreadHandle;

    //创建服务器工作线程,并且向线程传送完成端口

    if ((ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompetionPort,0,&ThreadID)) == NULL)

    {

      printf("CreateThread failed with error %d"n" ,GetLastError());

      return 0;

    }

    CloseHandle(ThreadHandle);

 }

 

 //打开一个服务器socket

 if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)

 {

    printf("WSASocket() failed with error %d"n", WSAGetLastError());

    return 0;

 }

 InternetAddr.sin_family = AF_INET;

 InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

 InternetAddr.sin_port = htons(PORT);

 

 if (bind(Listen,(LPSOCKADDR)&InternetAddr,sizeof(InternetAddr)) == SOCKET_ERROR)

 {

    printf("bind failed with error %d"n",WSAGetLastError());

    return 0;

 }

 if (listen(Listen,5) == SOCKET_ERROR)

 {

    printf("listen failed with error %d"n",WSAGetLastError());

    return 0;

 }

 //接收连接并且分发给完成端口

 while (TRUE)

 {

    if ((Accept = WSAAccept(Listen,NULL,NULL,NULL,0)) == SOCKET_ERROR)

    {

     printf("WSAAccept failed with error %d"n",WSAGetLastError());

      return 0;

    }

    //创建与套接字相关的套接字信息结构

    if ((PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA))) == NULL)

    {

      printf("GlobalAlloc failed with error %d"n",GetLastError());

      return 0;

    }

   

    // Associate the accepted socket with the original completion port.

    printf("Socket number %d connected"n",Accept);

    PerHandleData->Socket = Accept;//结构中存入接收的套接字

   

    //与我们的创建的那个完成端口关联起来,将关键项也与指定的一个完成端口关联

    if ((CreateIoCompletionPort((HANDLE)Accept,CompetionPort,(DWORD)PerHandleData,0)) == NULL)

    {

      printf("CreateIoCompletionPort failed with error%d"n",GetLastError());

      return 0;

    }

    // 创建同下面的WSARecv调用相关的IO套接字信息结构体

    if ((PerIOData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA))) = NULL)

    {

      printf("GlobalAloc failed with error %d"n",GetLastError());

      return 0;

    }

    ZeroMemory(&(PerIOData->OVerlapped),sizeof(OVERLAPPED));

    PerIOData->BytesRecv = 0;

    PerIOData->BytesSend = 0;

    PerIOData->DATABuf.len = DATA_BUFSIZE;

    PerIOData->DATABuf.buf = PerIOData->Buffer;

    Flags = 0;

    if (WSARecv(Accept,&(PerIOData->DATABuf),1,&RecvBytes,&Flags,&(PerIOData->OVerlapped),NULL) == SOCKET_ERROR)

    {

     if (WSAGetLastError() != ERROR_IO_PENDING)

     {

       printf("WSARecv() failed with error %d"n",WSAGetLastError());

       return 0;

     }

    }

 }

 return 0;

}

//工作线程

DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID)

{

 HANDLE ComplectionPort = (HANDLE) ComlpetionPortID;

 DWORD BytesTransferred;

 LPOVERLAPPED Overlapped;

 LPPER_HANDLE_DATA PerHandleData;

 LPPER_IO_OPERATION_DATA PerIOData;

 DWORD SendBytes,RecvBytes;

 DWORD Flags;

 

 while (TRUE)

 {

    if (GetQueuedCompletionStatus(ComplectionPort,&BytesTransferred,(LPDWORD)&PerHandleData,(LPOVERLAPPED*)&PerIOData,INFINITE) == 0)

    {

      printf("GetQueuedCompletionStatus failed with error%d"n",GetLastError());

      return 0;

    }

    //首先检查套接字上是否发生错误,如果发生了则关闭套接字并且清除同套节字相关的SOCKET_INFORATION 结构体

    if (BytesTransferred == 0)

    {

      printf("Closing Socket %d"n",PerHandleData->Socket);

      if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)

      {

        printf("closesocket failed with error %d"n",WSAGetLastError());

        return 0;

      }

      GlobalFree(PerHandleData);

      GlobalFree(PerIOData);

      continue;

    }

    //检查BytesRecv域是否等于0,如果是,说明WSARecv调用刚刚完成,可以用从己完成的WSARecv调用返回的BytesTransferred值更新BytesRecv

    if (PerIOData->BytesRecv == 0)

    {

      PerIOData->BytesRecv = BytesTransferred;

      PerIOData->BytesSend = 0;

    }

    else

    {

      PerIOData->BytesRecv +=BytesTransferred;

    }

    //

    if (PerIOData->BytesRecv > PerIOData->BytesSend)

{

       //发布另一个WSASend()请求,因为WSASendi 不能确保发送了请的所有字节,继续WSASend调用直至发送完所有收到的字节

      ZeroMemory(&(PerIOData->OVerlapped),sizeof(OVERLAPPED));

      PerIOData->DATABuf.buf = PerIOData->Buffer + PerIOData->BytesSend;

      PerIOData->DATABuf.len = PerIOData->BytesRecv - PerIOData->BytesSend;

     

      if (WSASend(PerHandleData->Socket,&(PerIOData->DATABuf),1,&SendBytes,0,&(PerIOData->OVerlapped),NULL) ==SOCKET_ERROR )

      {

        if (WSAGetLastError() != ERROR_IO_PENDING)

        {

          printf("WSASend() fialed with error %d"n",WSAGetLastError());

          return 0;

        }

      }

    }

    else

    {

      PerIOData->BytesRecv = 0;

      //Now that is no more bytes to send post another WSARecv() request

      //现在己经发送完成

      Flags = 0;

      ZeroMemory(&(PerIOData->OVerlapped),sizeof(OVERLAPPED));

      PerIOData->DATABuf.buf = PerIOData->Buffer;

      PerIOData->DATABuf.len = DATA_BUFSIZE;

      if (WSARecv(PerHandleData->Socket,&(PerIOData->DATABuf),1,&RecvBytes,&Flags,&(PerIOData->OVerlapped),NULL) == SOCKET_ERROR)

      {

        if (WSAGetLastError() != ERROR_IO_PENDING)

        {

          printf("WSARecv() failed with error %d"n",WSAGetLastError());

          return 0;

        }

      }

    }

 }

 

}

原文地址:https://www.cnblogs.com/madlas/p/1419966.html