zoukankan      html  css  js  c++  java
  • IOCP模型TCP服务器

    主线程创建监听套接字,创建额外工作线程,关联IOCP,负责等待和接受到来的连接。

    调用GetQueuedCompletionStatus函数,函数返回:

    1 调用失败

    2 套接字被对方关闭

    3 请求成功完成

    程序首先定义per-handle per-IO的操作数据的结构类型

    #define BUFFER_SIZE 1024
    typedef struct _PER_HANDLE_DATA{
        SOCKET s;
        sockaddr_in addr;
    }PER_HANDLE_DATA,*PPER_HANDLE_DATA;
    typedef struct _PER_IO_DATA{
        OVERLAPPED ol;
        char buf[BUFFER_SIZE];
        int nOperationType;
    #define OP_READ 1
    #define OP_WRITE 2
    #define OP_ACCEPT 3
    }PER_IO_DATA,*PPER_IO_DATA;

    主要过程:

    1 主线程创建完成端口对象,创建工作线程处理完成端口对象中的事件

    2 创建监听套接字,开始监听服务器端口

    3 进入无限循环,处理到来的请求

      1)调用accept函数等待接受未决的连接请求   2)创建一个per-handle数据   3)投递一个接收请求

    实现代码:

    void  main()
    {
        int nPort = 4567;
        HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
        ::CreateThread(NULL,0,ServerThread,(LPVOID)hCompletion,0,0);
    
        SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,0);
        SOCKADDR_IN si;
        si.sin_family = AF_INET;
        si.sin_port = htons(nPort);
        si.sin_addr.S_un.S_addr = INADDR_ANY;
        ::bind(sListen,(sockaddr*)&si,sizeof(si));
        ::listen(sListen,5);
        while(TRUE){
            //等待接收未决的请求
            SOCKADDR_IN saRemote;
            int nRemoteLen = sizeof(saRemote);
            SOCKET sNew = ::accept(sListen,(sockaddr*)&saRemote,&nRemoteLen);
            //创建per-handle
            PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
            pPerHandle->s = sNew;
            memcpy(&pPerHandle->addr,&saRemote,nRemoteLen);
            ::CreateIoCompletionPort((HANDLE)pPerHandle->s,hCompletion,(DWORD)pPerHandle,0);
            //投递一个接收请求
            PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR,sizeof(PER_IO_DATA));
            pPerIO->nOperationType = OP_READ;
            WSABUF buf;
            buf.buf = pPerIO->buf;
            buf.len = BUFFER_SIZE;
            DWORD dwRecv;
            DWORD dwFlags = 0;
            ::WSARecv(pPerHandle->s,&buf,1,&dwRecv,&dwFlags,&pPerIO->ol,NULL);//接收投递求
        }
    }
    DWORD WINAPI ServerThread(LPVOID lpParam{
        HANDLE hCompletion = (HANDLE)lpParam;
        DWORD dwTrans;
        PPER_HANDLE_DATA pPerHandle;
        PPER_IO_DATA pPerIO;
        while(TRUE){
            BOOL bOK = ::GetQueuedCompletionStatus(hCompletion,&dwTrans,(LPDWORD)&pPerHandle,(LPOVERLAPPED*)&pPerIO,WSA_INFINITE);
            if(!bOK)
            {
                ::closesocket(pPerHandle->s);
                ::GlobalFree(pPerHandle);
                ::GlobalFree(pPerIO);
                continue;
            }
            if(dwTrans == 0 && (pPerIO->nOperationType==OP_READ||pPerIO->nOperationType==OP_WRITE))
            {
                ::closesocket(pPerHandle->s);
                ::GlobalFree(pPerHandle);
                ::GlobalFree(pPerIO);
                continue;
            }
            switch(pPerIO->nOperationType)
            {
            case OP_READ:
                {
                    pPerIO->buf[dwTrans] = '\0';
                    printf(pPerIO->buf);
                    WSABUF buf;
                    buf.buf = pPerIO->buf;
                    buf.len = BUFFER_SIZE;
                    pPerIO->nOperationType = OP_READ;
                    DWORD nFlags = 0;
                    ::WSARecv(pPerHandle->s,&buf,1,&dwTrans,&nFlags,&pPerIO->ol,NULL);
                }
                break;
            case OP_WRITE:
            case OP_ACCEPT:
                break;
            }
        }
        return 0;
    }
  • 相关阅读:
    如何在for循环中使用多线程
    解决ios10以上H5页面手势、双击缩放问题
    select标签默认选项
    vue三级联动
    手动安装composer详细教学
    密码校验:长度6位以上,至少包含一个数字,一个大写字母,一个小写字母,不包含空格
    tp5生成6位不重复验证码
    css漂亮的阴影边框
    圆形进度条css3样式
    jQuery倒计时组件(jquery.downCount.js)
  • 原文地址:https://www.cnblogs.com/xing901022/p/2728316.html
Copyright © 2011-2022 走看看