UDP IOCP ser

// iocpser.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>

#define PORT     9090
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")

typedef enum
{
   RECV_POSTED
}OPERATION_TYPE;       //枚舉,表示狀態
typedef struct
{
WSAOVERLAPPED   overlap;
WSABUF          Buffer;
char            szMessage[MSGSIZE];
struct sockaddr_in addr;
DWORD           NumberOfBytesRecvd;
DWORD           Flags;
OPERATION_TYPE OperationType;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;    //定義一個結構體保存IO數據
DWORD WINAPI WorkerThread(LPVOID);
int main()
{
WSADATA                  wsaData;
SOCKET                   sListen, sClient;
SOCKADDR_IN              local, client;
DWORD                    i, dwThreadId;
int                      iaddrSize = sizeof(SOCKADDR_IN);
HANDLE                   CompletionPort = INVALID_HANDLE_VALUE;
HANDLE                   CompletionPort2 = INVALID_HANDLE_VALUE;
SYSTEM_INFO              systeminfo;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
INT32  fromaddr=sizeof(struct sockaddr_in);
UINT32 iocperrnum,recv=0;
//初始化Socket
WSAStartup(0x0202, &wsaData);
// 初始化完成端口
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// 有幾個CPU就創建幾個工作者線程
GetSystemInfo(&systeminfo);
for(i = 0; i < systeminfo.dwNumberOfProcessors+2; i++)
{
   CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
}
// 創建套接字
sListen = socket(AF_INET, SOCK_DGRAM, 0);
// 綁定套接字
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));
// 開始監聽!
//listen(sListen, 3);
//主進程的這個循環中循環等待客戶端連接,若有連接,則將該客戶套接字於完成端口綁定到一起
//然後開始異步等待接收客戶傳來的數據。
while (TRUE)
{
   // 如果接到客戶請求連接,則繼續,否則等待。
  // sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
   //client中保存用戶信息。
  // printf("Accepted client:%s:%dn", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
   //將這個最新到來的客戶套接字和完成端口綁定到一起。
   //第三個參數表示傳遞的參數,這裏就傳遞的客戶套接字地址。
   //最後一個參數爲0 表示有和CPU一樣的進程數。即1個CPU一個線程
  CompletionPort2= CreateIoCompletionPort((HANDLE)sListen, CompletionPort, ( ULONG_PTR)sListen, 4);
  if(CompletionPort2!=CompletionPort)
	  return 0;
//第三個sClient是傳遞的參數,傳給了後面的線程函數的GetQueuedCompletionStatus了
   
   // 初始化結構體 使用堆內存分配
   lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_OPERATION_DATA));
   
   lpPerIOData->Buffer.len = MSGSIZE; // len=1024
   lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
   lpPerIOData->NumberOfBytesRecvd=MSGSIZE;
   lpPerIOData->OperationType = RECV_POSTED; //操作類型
   lpPerIOData->Flags=0;
   
  while(1)
 {
   recv=WSARecvFrom(sListen,
	   &lpPerIOData->Buffer,
	   1,
	   &lpPerIOData->NumberOfBytesRecvd,
	   &lpPerIOData->Flags,
	   (struct sockaddr*)&lpPerIOData->addr,
	   &fromaddr,
	   &lpPerIOData->overlap,
	   NULL
	   );
   
   //Sleep(1); 
  
   iocperrnum= WSAGetLastError();
   /*
   WSARecv(sClient,      //異步接收消息,立刻返回。
     &lpPerIOData->Buffer,   //獲得接收的數據
     1,        //The number of WSABUF structures in the lpBuffers array.
     &lpPerIOData->NumberOfBytesRecvd, //接收到的字節數,如果錯誤返回0
     &lpPerIOData->Flags,   //參數,先不管
     &lpPerIOData->overlap,   //輸入這個結構體咯。
     NULL);
	 */
  }
   printf("WSARecv 1 \n");
  }

//向每個工作者線程都發送—個特殊的完成數據包。該函數會指示每個線程都“立即結束並退出”.
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;
INT32 fromaddr=sizeof(struct sockaddr);
UINT32 recv;
while (TRUE)
{
    printf("enter WorkerThread \n");
         //無限等待咯。不超時的那種。
   if( GetQueuedCompletionStatus(    //遇到可以接收數據則返回,否則等待
    CompletionPort,
    &dwBytesTransferred,    //返回的字數
    (PULONG_PTR)&sClient,           //是響應的哪個客戶套接字?
    (LPOVERLAPPED *)&lpPerIOData, //得到該套接字保存的IO信息
	INFINITE)==FALSE  )
	return 1;
   if (dwBytesTransferred == 0xFFFFFFFF)
   {
	   printf("dwBytesTransferred = 0xFFFFFFFF \n");
    return 0;
   }
       if (dwBytesTransferred == 0)
    {
		printf("dwBytesTransferred = 0 \n");
     //失去客戶端連接
     closesocket(sClient);
     HeapFree(GetProcessHeap(), 0, lpPerIOData);        //釋放結構體
    }
   if(lpPerIOData->OperationType == RECV_POSTED) //如果收到數據
   {


    
     //lpPerIOData->szMessage[dwBytesTransferred] = ' ';//收到的數據最後一位是結束標誌
	 
		printf("Message get:%d  ,%s \n",lpPerIOData->addr.sin_addr.S_un.S_addr,lpPerIOData->Buffer.buf);

	 //sendto(sClient, lpPerIOData->Buffer.buf, lpPerIOData->Buffer.len, 0,(struct sockaddr*)&lpPerIOData->addr,sizeof(struct sockaddr)); //將接收到的消息返回
        
     // Launch another asynchronous operation for sClient
    /* memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
       lpPerIOData->Buffer.len = MSGSIZE; // len=1024
	   lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
	   lpPerIOData->NumberOfBytesRecvd=MSGSIZE;
	   lpPerIOData->OperationType = RECV_POSTED; //操作類型
	   lpPerIOData->Flags=0;
	

	   recv=WSARecvFrom(sClient,
	   &lpPerIOData->Buffer,
	   1,
	   &lpPerIOData->NumberOfBytesRecvd,
	   &lpPerIOData->Flags,
	   (struct sockaddr*)&lpPerIOData->addr,
	   &fromaddr,
	   &lpPerIOData->overlap,
	   NULL
	   );
	   printf("recv %d",recv);

	   */
	   /*
     WSARecv(sClient,               //循環接收
       &lpPerIOData->Buffer,
       1,
       &lpPerIOData->NumberOfBytesRecvd,
       &lpPerIOData->Flags,
       &lpPerIOData->overlap,
       NULL);
	   */
   
   }
   }
   return 0;
}
 


























/*
#pragma argsused
#pragma comment(lib,"ws2_32.lib")
#include <stdio.h>
#include <memory.h>
#include <winsock2.h>
#include <iostream>
using namespace std;

#define RECV_POSTED 1001
#define SEND_POSTED 1002

int Init();

HANDLE hCompletionPort;
typedef struct _PER_HANDLE_DATA
{
    SOCKET sock;
}PER_HANDLE_DATA,* LPPER_HANDLE_DATA;

typedef struct _PER_IO_OPERATION_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuff[1];
    char Buff[24];
    BOOL OperationType;
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort);

int main(int argc, char* argv[])
{
    LPPER_HANDLE_DATA perHandleData;
    LPPER_IO_OPERATION_DATA ioperdata;
    SYSTEM_INFO siSys;
    SOCKET sockListen;
    struct sockaddr_in addrLocal;
    char buf[24];
    int nRet = 0;
    DWORD nThreadID;
    SOCKET sockAccept;
    DWORD dwFlags;
    DWORD dwRecvBytes;
    int nReuseAddr = 1;

    cout<<"初始環境..."<<endl;
    if(Init() != 0)
        goto theend;

    //創建一個IO完成端口
    cout<<"創建一個IO完成端口"<<endl;
    hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
    if(hCompletionPort == INVALID_HANDLE_VALUE)
    {
        cout<<"創建IO完成端口失敗"<<endl;
        goto theend;
    }
    //獲取CPU數目
    GetSystemInfo(&siSys);
    //創建一定數目的工作者線程,本例中以一個處理器一個線程搭配
    for(int i = 0;i<(int)siSys.dwNumberOfProcessors*2;i++)//NumberOfProcessors
    {
        HANDLE hThread;
        hThread = CreateThread(NULL,0,ServerWorkerThread,(LPVOID)hCompletionPort,0,&nThreadID);
        cout<<"創建工作者線程"<<i<<endl;
        CloseHandle(hThread);
    }
    //創建監聽SOCKET
    cout<<"創建監聽SOCKET"<<endl;
    sockListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    if(sockListen == SOCKET_ERROR)
    {
        cout<<"WSASocket錯誤"<<endl;
        goto theend;
    }

    if(setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,(const char *)&nReuseAddr,sizeof(int)) != 0)
    {
        cout<<"setsockopt錯誤"<<endl;
        goto theend;
    }
    addrLocal.sin_family = AF_INET;
    addrLocal.sin_addr.s_addr = htonl(INADDR_ANY);
    addrLocal.sin_port = htons(9090);
    if(bind(sockListen,(struct sockaddr *)&addrLocal,sizeof(sockaddr_in)) != 0)
    {
        cout<<"bind錯誤"<<endl;
        int n = WSAGetLastError();
        goto theend;
    }
    //準備監聽
    cout<<"準備監聽"<<endl;
    if(listen(sockListen,5)!=0)
    {
        cout<<"listen錯誤"<<endl;
        goto theend;
    }
    while(true)
    {
        //接收用戶連接,被和完成端口關聯
        sockAccept = WSAAccept(sockListen,NULL,NULL,NULL,0);
        perHandleData = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
        if(perHandleData == NULL)
            continue;
        cout<<"socket number "<<sockAccept<<"接入"<<endl;
        perHandleData->sock = sockAccept;

        ioperdata = (LPPER_IO_OPERATION_DATA)malloc(sizeof(PER_IO_OPERATION_DATA));
        memset(&(ioperdata->Overlapped),0,sizeof(OVERLAPPED));
        (ioperdata->DataBuff[0]).len = 24;
        (ioperdata->DataBuff[0]).buf = ioperdata->Buff;
        ioperdata->OperationType = RECV_POSTED;
        if( ioperdata == NULL)
        {
            free(perHandleData);
            continue;
        }
        //關聯
        cout<<"關聯SOCKET和完成端口"<<endl;
        if(CreateIoCompletionPort((HANDLE)sockAccept,hCompletionPort,(DWORD)perHandleData,1) == NULL)
        {
            cout<<sockAccept<<"createiocompletionport錯誤"<<endl;
            free(perHandleData);
            free(ioperdata);
            continue;
        }
        //投遞接收操作
        cout<<"投遞接收操作"<<endl;
        WSARecv(perHandleData->sock,ioperdata->DataBuff,1,&dwRecvBytes,&dwFlags,&(ioperdata->Overlapped),NULL);
    }
theend:
    getchar();
    return 0;
}
//---------------------------------------------------------------------------
int Init()
{
    WSAData wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
    {
        cout<<"WSAStartup失敗"<<endl;
        return -1;
    }

    if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        cout<<"SOCKET版本不對"<<endl;
        WSACleanup();
        return -1;
    }
    return 0;
}

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort)
{
    HANDLE ComPort = (HANDLE)CompletionPort;
    DWORD BytesTransferred;
    LPOVERLAPPED Overlapped;
    LPPER_HANDLE_DATA PerHandleData;
    LPPER_IO_OPERATION_DATA PerIoData;
    DWORD SendBytes,RecvBytes;
    DWORD Flags;
    BOOL bT;

    while(TRUE)
    {
        //等待完成端口上SOCKET的完成
        cout<<"等待完成端口上SOCKET的完成"<<endl;
        bT = GetQueuedCompletionStatus(ComPort,
            &BytesTransferred,(LPDWORD)&PerHandleData,
            (LPOVERLAPPED *)&PerIoData,INFINITE);

        //檢查是否有錯誤產生
        if(BytesTransferred == 0 &&
            (PerIoData->OperationType == RECV_POSTED ||
            PerIoData->OperationType == SEND_POSTED))
        {
            //關閉SOCKET
            cout<<PerHandleData->sock<<"SOCKET關閉"<<endl;
            closesocket(PerHandleData->sock);
            free(PerHandleData);
            free(PerIoData);
            continue;
        }

        //爲請求服務
        
        if(PerIoData->OperationType == RECV_POSTED)
        {
            //處理
            cout<<"接收處理"<<endl;
            cout<<PerHandleData->sock<<"SOCKET :"<<PerIoData->Buff<<endl;
            //迴應客戶端
            ZeroMemory(PerIoData->Buff,24);
            strcpy(PerIoData->Buff,"OK");
            Flags = 0;
            ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
            PerIoData->DataBuff[0].len = 2;
            PerIoData->DataBuff[0].buf = PerIoData->Buff;
            PerIoData->OperationType = SEND_POSTED;
            WSASend(PerHandleData->sock,PerIoData->DataBuff,
                1,&SendBytes,0,&(PerIoData->Overlapped),NULL);
        }
        else //if(PerIoData->OperationType == SEND_POSTED)
        {
            //發送時的處理
            cout<<"發送處理"<<endl;
            Flags = 0;
            ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
            ZeroMemory(PerIoData->Buff,24);
            PerIoData->DataBuff[0].len = 24;
            PerIoData->DataBuff[0].buf = PerIoData->Buff;
            PerIoData->OperationType = RECV_POSTED;
            WSARecv(PerHandleData->sock,PerIoData->DataBuff,
                1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
        }
    }
}
*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章