初学完成端口的实例代码

//
//  完成端口
//
//
//

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

int InitSock();
DWORD WINAPI SerWorkThread(LPVOID CompletionPort);

// PerHandleData
typedef struct _PER_HANDLE_DATA
{
 SOCKET socket;
 SOCKADDR_IN ClientAddr;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;

// Per IO operation Data
typedef struct _PER_IO_OPERATION_DATA
{
 OVERLAPPED Overlapped;
 WSABUF DataBuf;
 CHAR Buffer[8192];
 DWORD BytesSEND;
 DWORD BytesRECV;
}PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;


int main(int argc, char* argv[])
{
 HANDLE hCompletionPort;
 SYSTEM_INFO sysInfo;
 int i = 0;
 SOCKET Listen;
 SOCKET Accept;
 SOCKADDR_IN InetAddr;
 DWORD Flags = 0;
 DWORD RecvBytes = 0;
 SOCKADDR_IN saRemote;
 int saRemoteLen = sizeof(saRemote); 
 LPPER_HANDLE_DATA PerHandleData=NULL;
 LPPER_IO_OPERATION_DATA PerIoOperationData=NULL;
 
 if (!InitSock()) {
  printf("InitSock Error!/n");
  return 0;
 }
 //创建完成端口
 hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
 if (hCompletionPort == NULL) {
  printf("Creatae CompletionPort Error!!/n");
  return 0;
 }
 
 //创建工作者线程,线程数量和CPU数量保持一致
 //工作者线程在IO请求到来的时候为完成端口提供服务。
 GetSystemInfo(&sysInfo);
 for ( i=0; i < (int)sysInfo.dwNumberOfProcessors ; i++ )
 {
  HANDLE hThread;
  hThread = CreateThread(NULL,0,SerWorkThread,hCompletionPort,0,NULL);
  if (hThread ==  NULL) {
   printf("CreateThread Fail!");
  }
  CloseHandle(hThread);
 }
 
 //注意这里的SOCKET是TCP的
 Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); 
 if (Listen == INVALID_SOCKET){
  printf("Listen's socket error!/n");
  return 0;
 }
 InetAddr.sin_family = AF_INET;
 InetAddr.sin_port   = htons(5010);
 InetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 
 if ( bind(Listen,(SOCKADDR*)&InetAddr,
  sizeof(SOCKADDR))== SOCKET_ERROR) {
  printf("Bind error/n");
  return 0;
 }
 if ( listen(Listen,5)==SOCKET_ERROR ) {  //注意这里的第二个参数
  printf("Listen error/n");
  return 0;
 }
 
 while (TRUE)
 {
  Accept = WSAAccept(Listen,(SOCKADDR*)&saRemote,&saRemoteLen,NULL,NULL);
  if (Accept == SOCKET_ERROR) {
   printf("Accept error/n");
  }
  //set Per-handle Data
  PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
  if (PerHandleData == NULL) {
   printf("GlobalAlloc momery error!");
   return 0;
  }
  printf("Socket number %d connected./n ",Accept);
  PerHandleData->socket = Accept;
  memcpy(&PerHandleData->ClientAddr,&saRemote,saRemoteLen);
  //PerHandleData  包含了与套接字相关的其他信息
  if ( CreateIoCompletionPort((HANDLE)Accept,hCompletionPort,(DWORD)PerHandleData,0) == NULL ) {
   printf("CreateCompletionPort Error!");
   return 0;
  }
  
  PerIoOperationData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(
        GPTR,sizeof(PER_IO_OPERATION_DATA));
  ZeroMemory(&(PerIoOperationData->Overlapped),sizeof(OVERLAPPED));
  PerIoOperationData->BytesSEND = 0;
  PerIoOperationData->BytesRECV = 0;
  PerIoOperationData->DataBuf.buf = PerIoOperationData->Buffer;
  PerIoOperationData->DataBuf.len = 8192;
  
  Flags = 0;
  if (WSARecv(Accept, &(PerIoOperationData->DataBuf), 1, &RecvBytes, &Flags,
   &(PerIoOperationData->Overlapped), NULL) == SOCKET_ERROR) {

   if (WSAGetLastError() != ERROR_IO_PENDING)
   {
            printf("WSARecv() failed with error %d/n", WSAGetLastError());
            return;
   }
  }
 }
}

int  InitSock(void)
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 
 wVersionRequested = MAKEWORD( 2, 2 );
 
 err = WSAStartup( wVersionRequested, &wsaData );
 if (err != 0 ) {
  return 0;
 }
 if (LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
  WSACleanup();
  return 0;
 }
 return 1;
}


DWORD WINAPI SerWorkThread(LPVOID CompletionPortID)
{
 HANDLE CompletionPort = (HANDLE)CompletionPortID;
 DWORD BytesTransferred;
 // LPOVERLAPPED Overlapped;
 LPPER_HANDLE_DATA PerHandleData;
 LPPER_IO_OPERATION_DATA PerIoData;
 DWORD SendBytes,RecvBytes;
 DWORD Flags;
 
 while(TRUE)
 {
  //获得完成端口队列状态,在这里会把IO操作的后的信息传入PerHandleData,PerIoData
  if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
   (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
  {
   printf("GetQueuedCompletionStatus failed with error %d/n", GetLastError());
   return 0;
  }  

  //BytesTransferred在完成一次IO操作后,接受/传输的实际字符数
  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;
  }
  
  if (PerIoData->BytesRECV == 0)
  {
   PerIoData->BytesRECV = BytesTransferred;
   PerIoData->BytesSEND = 0;
  }
  else
  {
   PerIoData->BytesSEND += BytesTransferred;
  }
  
  if (PerIoData->BytesRECV > PerIoData->BytesSEND)
  {
   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() failed with error %d/n", WSAGetLastError());
     return 0;
    }
   }
  }
  else
  {
   PerIoData->BytesRECV = 0;
   Flags = 0;
   ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
   PerIoData->DataBuf.len = 8192;
   PerIoData->DataBuf.buf = PerIoData->Buffer;
   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;
    }
   }
   else
   {//将接受到的消息打印出来
    printf("%s",&PerIoData->DataBuf);
   }
  }
 } 
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值