1. 程式人生 > >老早寫過的IOCP模型demo程式碼;

老早寫過的IOCP模型demo程式碼;

僅供參考下!

#ifndef __IOCPMODEL_H
#define __IOCPMODEL_H

#include <iostream>
#include <WinSock2.h>

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


#define OP_READ 1
#define OP_WRITE 2
#define OP_ACCEPT 3
#define OP_END -1

#define BUFFER_SIZE 1024

using namespace std;
//自定義結構,即“完成鍵”(單控制代碼資料)
typedef struct tagPER_HANDLE_DATA
{
    SOCKET Socket;
    SOCKADDR_STORAGE ClientAddr;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;

//單個I/O操作資料
typedef struct tagPer_IO_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    char buffer[1024];
    int BufferLen;
    int OperationType;            //IO操作型別

}PER_IO_DATA, *LPPER_IO_DATA;

//執行緒方法
DWORD WINAPI ServerWorkerThread(LPVOID lpParam);


#endif

CPP檔案

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

#include "stdafx.h"
#include "IocpModel.h"

#define Op_READ 1
#define Op_WRITE 2




WSADATA wsa;
HANDLE CompletionPort;
SYSTEM_INFO Systeminfo;
SOCKADDR_IN InternetAddr;

HANDLE ThreadHanle;


void ChangeHandleData(LPPER_IO_DATA lpPerIoContext,int state)
{
/**
    Fucntion Description:
        根據傳進來的state,來進行改變下一步的IO操作
    Parameter:
        lpPerIoContext:上一個IO操作的結果
        state           上一個IO操作的狀態
    Return Value:
        返回值為空
**/
    if(OP_READ == state)
    {
        //完成了讀取客戶端資料,並且返回資料
        lpPerIoContext->OperationType = OP_WRITE;
        ZeroMemory(&(lpPerIoContext->Overlapped),sizeof(OVERLAPPED));
        //返回資料給客戶端
        char *sendClientData = "sendClientData";
        lpPerIoContext->DataBuf.buf = sendClientData;
        lpPerIoContext->DataBuf.len = BUFFER_SIZE;
    }
    if(OP_WRITE == state)
    {    
        //上一個IO資料傳送客戶端完成,結束就用 OP_END
        //繼續接受,叫型別設定為OP_READ,注意清空下 buff
        //繼續傳送,將資料設定為OP_WRITE
        lpPerIoContext->OperationType = OP_READ;
        lpPerIoContext->DataBuf.buf = lpPerIoContext->buffer;
        lpPerIoContext->DataBuf.len = BUFFER_SIZE;
    }
    if(OP_ACCEPT == state)
    {
        //立起來的連線,把控制代碼設為讀型別
        lpPerIoContext->OperationType = OP_READ;
        ZeroMemory(&(lpPerIoContext->Overlapped),sizeof(OVERLAPPED));
        ZeroMemory(&(lpPerIoContext->DataBuf),sizeof(lpPerIoContext->DataBuf));
        lpPerIoContext->DataBuf.buf = lpPerIoContext->buffer;
        lpPerIoContext->DataBuf.len = BUFFER_SIZE;
        cout << "資料包操作型別被改為 : OP_READ"<<endl;
    }
}

void SendHandleData(LPPER_IO_DATA lpPerIoContext,LPPER_HANDLE_DATA perHandData)
{
    /**
        根據lpPerIoContext物件OperationType來進行下一步的操作
    **/
    DWORD dwIosize = 0;
    int nResult  =0;
    DWORD RecvBytes = 0;
    DWORD nFlag = 0;
    if(lpPerIoContext->OperationType  == OP_WRITE)
    {
        /*傳送資料到客戶端*/
        nResult = WSASend(perHandData->Socket,&(lpPerIoContext->DataBuf),1,&dwIosize,0,&(lpPerIoContext->Overlapped),NULL);
        if((nResult == SOCKET_ERROR) && WSAGetLastError() != ERROR_IO_PENDING )
        {
            cout<< "WSASend error :"<<WSAGetLastError()<<endl;
            ::closesocket(perHandData->Socket);
            return;
        }

    }
    else if(lpPerIoContext->OperationType == OP_READ)
    {
        //清空,準備下個I/O資料
        ZeroMemory(&(lpPerIoContext->Overlapped),sizeof(OVERLAPPED));
        //注意:這裡清空下buffer,要不然資料會跟上一條粘在一起
        ZeroMemory(&(lpPerIoContext->buffer),sizeof(lpPerIoContext->buffer));
        lpPerIoContext->DataBuf.len = BUFFER_SIZE;
        if(SOCKET_ERROR == WSARecv(perHandData->Socket, &(lpPerIoContext->DataBuf), 1,&RecvBytes,&nFlag,&(lpPerIoContext->Overlapped),NULL)){
            cout << "WSARecv() failed: " << WSAGetLastError() << endl;
            return;
        }
    }
    else if(lpPerIoContext->OperationType == OP_END)
    {
        ::closesocket(perHandData->Socket);
    }
}

int main()
{
    SOCKET ListenSock;
    SOCKET accpSocket;
    PER_HANDLE_DATA *PerHandleData = NULL;
    SOCKADDR_IN saRemote;
    int RemoteLen;

    cout<<"Server start......"<<endl;
    WSAStartup(MAKEWORD(2,2),&wsa);
    GetSystemInfo(&Systeminfo);

    //建立一個IO完成埠
    CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
    if ( CompletionPort == INVALID_HANDLE_VALUE ) 
    {
        cout<<"完成埠建立失敗!!!!"<<endl;
        return 0;
    }

    //建立IOCP工作執行緒(根據CPU個數 * 2)
    for(int i = 0;i< Systeminfo.dwNumberOfProcessors * 2 ; ++ i)
    {
        //建立執行緒
        ThreadHanle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,NULL);
        CloseHandle(ThreadHanle);
    }

    //4. 建立一個監聽套接字,
    ListenSock = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    if(ListenSock == INVALID_SOCKET)
    {
        cout<<"套接字建立 失敗!!"<<endl;
        return 0;
    }

    InternetAddr.sin_family = AF_INET;
    InternetAddr.sin_port = htons(5000);
    InternetAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if(SOCKET_ERROR == bind(ListenSock,(SOCKADDR*)&InternetAddr,sizeof(InternetAddr)))
    {
        cout<<"伺服器繫結地址資訊 失敗!! errid:"<<GetLastError()<<endl;
        closesocket(ListenSock);
        return 0;
    }
    int ret = listen(ListenSock, 5);
    if (ret == SOCKET_ERROR)
    {
        cout<<"監聽套接字失敗!! errid:"<<GetLastError()<<endl;
        closesocket(ListenSock);
        return 0;
    }

    while(TRUE)
    {
        //接受連線
        RemoteLen = sizeof(saRemote);
        //accpSocket = WSAAccept(ListenSock,NULL,NULL,NULL,0);
        accpSocket = accept(ListenSock, (SOCKADDR*)&saRemote, &RemoteLen);
        if(SOCKET_ERROR == accpSocket)
        {
            cout<<"接受套接字錯誤!! errid:"<<GetLastError()<<endl;
            closesocket(accpSocket);
            return 0;
        }

        //建立用來和套接字關聯控制代碼資訊結構
        PerHandleData =(LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
        if(PerHandleData == NULL)
        {
            cout<<"PerHandleData = null!! errid:"<<GetLastError()<<endl;
            closesocket(accpSocket);
            return 0;
        }
        cout<< "Socker number: "<< accpSocket << " connected" << endl;
        PerHandleData->Socket = accpSocket;
        memcpy(&PerHandleData->ClientAddr,&saRemote,RemoteLen);


        //將接受的套接字關聯到 完成埠
        if(CreateIoCompletionPort((HANDLE)accpSocket,CompletionPort,(DWORD)PerHandleData,0) == NULL)
        {
            cout<<"create complertion port error! errid:"<<GetLastError()<<endl;
            return 0;
        }

        LPPER_IO_DATA PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));;
        ChangeHandleData(PerIoData,OP_ACCEPT);
        SendHandleData(PerIoData,PerHandleData);
    }
    return 0;
}


//建立執行緒函式
DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
    HANDLE CompletionPort = (HANDLE)lpParam;
    DWORD ByresTransferred;
    LPOVERLAPPED lpOverlapped = NULL;
    LPPER_HANDLE_DATA PerHandleData = NULL;
    //LPPER_IO_DATA PerHandleData = NULL;
    LPPER_IO_DATA PerIoData = NULL;

    DWORD SendBytes;
    DWORD RecvBytes = 0;
    DWORD Flags = 0;
    BOOL bRet = FALSE;

    while (TRUE)
    {
        bRet = GetQueuedCompletionStatus(CompletionPort,
                                         &ByresTransferred,                    //的I/O操作所傳送資料的位元組數
                                         (PULONG_PTR)&PerHandleData,        //用於存放與之關聯的Completion鍵
                                         (LPOVERLAPPED*)&lpOverlapped,
                                          INFINITE);

        if(!bRet)
        {
            closesocket(PerHandleData->Socket);
            ::GlobalFree(PerHandleData);
            ::GlobalFree(PerIoData);
            ::GlobalFree(lpOverlapped);
            cout<< "失去客戶端連線!!!!" << bRet <<endl;
            return 0;
        }
        PerIoData = (LPPER_IO_DATA)lpOverlapped;

        //先檢查一下,看看是否套接字有錯誤發生
        if(0 == ByresTransferred)
        {
            if(SOCKET_ERROR  == closesocket(PerHandleData->Socket)){
                cout<< "ByresTransferred SOCKET_ERROR err:" << GetLastError() << endl;
            }
            ::GlobalFree(PerHandleData);
            ::GlobalFree(PerIoData);
            cout<< "發生錯誤! error" <<endl;
            continue;
        }

        
        //處理操作
        switch(PerIoData->OperationType)
        {
        case OP_ACCEPT:
            if(ByresTransferred)
            {
                //第一次連線接受到的資料
                ChangeHandleData(PerIoData,OP_ACCEPT);
                SendHandleData(PerIoData,PerHandleData);
            }
            else
            {
                //連線成功,資料沒接受到,繼續接受
                ChangeHandleData(PerIoData,OP_ACCEPT);
                SendHandleData(PerIoData,PerHandleData);
            }
            break;
        case OP_READ:
            cout<<"-----------------reader----------------------"<< endl;
            cout<<"傳送資料的位元組數:"<< ByresTransferred  <<endl;
            cout<<"接受資料為:"<<PerIoData->DataBuf.buf<< endl;
            cout<<"---------------------------------------------"<< endl;
            ChangeHandleData(PerIoData,OP_READ);
            SendHandleData(PerIoData,PerHandleData);
            break;
        case OP_WRITE:
            ChangeHandleData(PerIoData,OP_WRITE);
            SendHandleData(PerIoData,PerHandleData);
            break;
        default:
            //其他操作
            break;
            
        }
        
    }

    return 0 ;
}


相關推薦

老早IOCP模型demo程式碼

僅供參考下! #ifndef __IOCPMODEL_H #define __IOCPMODEL_H #include <iostream> #include <WinSock2.h> #pragma comment(lib,"ws2_32.

轉發:IOCP模型示例程式碼

#include <WinSock2.h> #include <Windows.h> #include <vector> #include <iostream> using namespace std; #pragma co

了8年的程式碼,做的專案都下線了,程式設計師的意義在哪裡!

一、起因 前幾天專案交付上線,所以閒下來了。忽然想起來,自己業餘接的活,有些專案已經不再運營了,所以想清理下域名解析。 上去阿里雲一看,總的大概有15個解析。這15個解析就意味著15個專案。這些專案都是我去談的需求、寫的文件、前後端開發、部署上線維護,整個專案幾乎都是我一人完成的。 想當初,很用心的去開

看看這些被同事噴的JS程式碼風格你多少

作者:殷榮檜@騰訊 目錄: 一、變數相關 二、函式相關 三、儘量使用ES6,有可以能的話ES7中新語法   現在寫程式碼比以前好多了,程式碼的格式都有eslint,prettier,babel(寫新版語法)這些來保證,然而,技術手段再高階都不能解決程式碼可讀性(程式碼能否被未來的自己和同事看懂)的問

程式設計師入職華為三個月沒程式碼:渴望提交程式碼,創造價值!

一名程式設計師,由於公司的專案情況,長期不能寫程式碼,你是什麼感受呢?是不是感覺很失落,大部分程式設計師都會有這種感覺吧,有的時候可能是研究一些技術,看一些程式碼什麼的,部分程式設計師就不願意幹這樣的事情,感覺還是自己寫程式碼爽,最近就有一名華為員工經歷了這樣一種情況!  

一個模型搞定所有風格轉換,直接在瀏覽器實現(demo+程式碼

用一個模型就能實現所有型別的風格轉換!一個名為Arbitrary Image Stylization in the Browser的專案最近火起來。 作者是日本小哥Reiichiro Nakano,他用TensorFlow.js在瀏覽器中構建了一個使用任意影象進行風格化的demo。 不像以前

Java - JDK8新特性,程式碼demo示例

哈哈哈哈大魔都下雪啦,敲段程式碼暖和暖和,嘿嘿 public class jdk8Test { @Test public void LambdaNew() { //before jdk8 List<String> names = Arrays.asList

了8年的程式碼,做的專案都下線了,程式設計師的意義在哪裡?

我堅信未來是我的,也是你的。但歸根結底是程式設計師的! ——忘記來自哪裡了 程式碼,正在改變世界。正是因為有了程式碼的存在,才有了百度、阿里巴巴、騰訊、京東、等的存在...... 下面是一位來自工作了八年的資深碼農的深刻感悟,正值“1024 程式設計

十行以內,你哪些比較酷的 Matlab 程式碼

最近正在寫一個模擬快速畫圖的GUI。 以下這段的功能是,點一下按鈕,就把打開了的Scope的圖直接儲存成jpg檔案。 以前的話基本都是用截圖工具,或者先把Scope的Menubar設定成可見,之後再Save as為影象。 刪掉了備註,剛好十行,可卻花了好幾天的時間找如何定位到特定object的方法…

從div盒子模型談如何可維護的css程式碼

在寫頁面之中,width, margin, padding這三個CSS屬性可以說是用到頻率最高的幾個屬性之一。但根據我的觀點來看,許多人,甚至於大多數前端對於這三個屬性的書寫把握上乏善可陳,以至於相容和靈活性不得兼顧,導致日後的開發維護成本直線上升,程式碼不斷增長,覆蓋重寫樣式,接著再修復一個又一個的Bu

netty的執行緒模型, 調優 及 獻上註釋的原始碼工程

Netty能幹什麼? Http伺服器 使用Netty可以編寫一個 Http伺服器, 就像tomcat那樣,能接受使用者傳送的http請求, , 只不過沒有實現Servelt規範, 但是它也能解析攜帶的引數, 對請求的路徑進行路由導航, 從而實現將不同的請求導向不同的handler進行處理 對socket與RP

主從復制2——擁有海量數據主服務器的主從復制模型詳細實現

海量數據的主從復制實現基本策略:此時需要在主服務器上先完全備份,還原到從服務器;接著開啟主從復制; 如果直接使用主從復制,那麽主從服務器的壓力很大;主服務器數據全備份操作: [root@master ~]$mysqldump -A -F --single-transaction --master-data=1

【HiJ1m】在NOIP2017前的有用的東西匯總

cnblogs 技巧 bst div 方程 ima alt 技術分享 pos http://www.cnblogs.com/Elfish/p/7544623.html 高級樹狀數組 http://www.cnblogs.com/Elfish/p/7554420.html

編程、代機器學習模型、代AI python

nal prolog 一份 行業 之間 標識 日期 軟件設計 環境 代寫編程、代寫機器學習模型基於不同的機器學習模型,利用大量的特征變量,對標的資產價格的波動進行預測研究,並對預測效果進行評價。機器學習的模型包括,但不限於XGBoost、GBDT、LSTM等經典學習模型。待

原生JS了一個小demo,根據輸入的數字生成不同背景顏色的小方塊兒~

top == UNC 定位元素 demo TE tostring eight 地方 昨天練習寫了這個小demo,個人覺得通過設置定位元素left和top的值,來實現換行的功能,這種方法很巧妙~ 另外,如下代碼中的隨機顏色的獲取,還請各位前輩多多指教:需要改進的地方;或者有

使用L2正則化和平均滑動模型的LeNet-5MNIST手數字識別模型

put 輸出矩陣 conv2 cross -m collect variable global 空間 使用L2正則化和平均滑動模型的LeNet-5MNIST手寫數字識別模型 覺得有用的話,歡迎一起討論相互學習~Follow Me 參考文獻Tensorflow實戰Googl

kaldi中文語音識別thchs30模型訓練程式碼功能和配置引數解讀

Monophone 單音素模型的訓練 # Flat start and monophone training, with delta-delta features. # This script applies ceps

從零開始的Python爬蟲速成指南,本文受眾:沒爬蟲的萌新

  引言 用最短的時間寫一個最簡單的爬蟲,可以抓一些簡單的論壇、帖子、網頁。 入門 1.準備工作 安裝Python 安裝scrapy框架 一個IDE或者可以用自帶的 2.開始寫爬蟲   &n

的部分板子

退役之前把自己敲過的板子都發一下,不會有詳細的解釋,只能保證碼風適合大部分人的閱讀習慣   你將會在這篇文章中看到這些模板:   ·快讀 ·最短路——dijkstra及spfa ·最小生成樹 ·LCA的tarjan演算法 ·強連通分量的tarjan演算法以及割點的tarja

出一段Python程式碼實現刪除一個list裡面的重複元素?

  方法1:使用set函式  s=set(list),然後再list(s)   方法2:append      1 def delList(L): 2 L1 = [] 3 for i in L: 4