zoukankan      html  css  js  c++  java
  • 基于重叠IO模型的 回显TCP服务器设计

    ---------------------1 套接字对象----------------------

    为每个套接字创建一个SOCKET_OBJ对象,记录与之相关的信息。

     typedef struct _SOCKET_OBJ{
        SOCKET s;
        int nOutstandingOps;//重叠IO数量
        LPFN_ACCEPTEX lpfnAcceptEx; //扩展AcceptEx指针
    }SOCKET_OBJ,*PSOCKET_OBJ;

    所有重叠IO提交到特定的套接字上,释放对应套接字对象,必须保证此套接字再没有重叠IO,即nOutstandingOps=0

    申请套接字对象,释放套接字对象的函数

     PSOCKET_OBJ GetSocketObj(SOCKET s){
         PSOCKET_OBJ pSocket = (PSOCKET_OBJ)::GlobalAlloc(GPTR,sizeof(SOCKET_OBJ));
         if(pSocket != NULL)
             pSocket->s = s;
         return pSocket;
     }
     void FreeSocketObj(PSOCKET_OBJ pSocket){
         if(pSocket->s != INVALID_SOCKET)
             ::closesocket(pSocket->s);
         ::GlobalFree(pSocket);
     }

    ---------------------2 缓冲区对象---------------------

    缓冲区对象SOCKET_OBJ,记录重叠IO的所有属性

     typedef struct _BUFFER_OBJ{
        OVERLAPPED ol;//重叠结构
        char *buff;//使用的缓冲区
        int nLen;//buff长度
        PSOCKET_OBJ pSocket;//次io所属的套接字对象
        int nOperation;//提交的操作类型
    #define OP_ACCEPT    1
    #define OP_READ        2
    #define OP_WRITE    3
        SOCKET sAccept;//保存AcceptEx接受客户套接字
        _BUFFER_OBJ *pNext;
     }BUFFER_OBJ,*PBUFFER_OBJ;

    pNext将BUFFER_OBJ对象练成一个链表

    事件句柄数组 和 链表地址

    HANDLE g_events[WSA_MAXIMUM_WAIT_EVENTS];
    int g_nBufferCount;//数量
    PBUFFER_OBJ g_pBufferHead,g_pBufferTail;//地址

    调用重叠IO函数之前,都要申请BUFFER_OBJ对象,记录信息。IO完成后,再释放BUFFER_OBJ对象

    申请BUFFER_OBJ对象 的函数:

    PBUFFER_OBJ GetBufferObj(PSOCKET_OBJ pSocket,ULONG nLen){
        if(g_nBufferCount > WSA_MAXIMUM_WAIT_EVENTS)
            return NULL;
        PBUFFER_OBJ pBuffer = (PBUFFER_OBJ)::GlobalAlloc(GPTR,sizeof(BUFFER_OBJ));
        if(pBuffer!=NULL)
        {
            pBuffer->buff = (char*)::GlobalAlloc(GPTR,nLen);
            pBuffer->ol.hEvent = ::WSACreateEvent();
            pBuffer->pSocket = pSocket;
            pBuffer->sAccept = INVALID_SOCKET;
    
            //将新的BUFFER_OBJ添加到列表
            if(g_pBufferHead == NULL)
            {
                g_pBufferHead = g_pBufferTail = pBuffer;
            }
            else
            {
                g_pBufferTail->pNext = pBuffer;
                g_pBufferTail = pBuffer;
            }
            g_events[++g_nBufferCount] = pBuffer->ol.hEvent;
        }
        return pBuffer;
    }

    释放BUFFER_OBJ对象函数:

    void FreeBufferObj(PBUFFER_OBJ pBuffer){
        //从列表中移除BUFFER_OBJ对象
        PBUFFER_OBJ pTest = g_pBufferHead;
        BOOL bFind = FALSE;
        if(pTest == pBuffer){
            g_pBufferHead = g_pBufferTail = NULL;
            bFind = TRUE;
        }
        else{
            while(pTest!=NULL && pTest->pNext!=pBuffer)
                pTest = pTest->pNext;
            if(pTest!=NULL){
                pTest->pNext = pBuffer->pNext;
                if(pTest->pNext == NULL)
                    g_pBuffer Tail = pTest;
                bFind = TRUE;
            }
        }
        //释放它占用的空间
        if(bFind)
        {
            g_pBufferCount--;
            ::CloseHandle(pBuffer->ol.hEvent);
            ::GlobalFree(pBuffer->buff);
            ::GlobalFree(pBuffer);
        }
    }

    提交重叠IO,传递参数有重叠结构IO和缓冲区指针buff。在IO完成后,得到的是受信事件对象的句柄。根据这个句柄找到对应的BUFFER_OBJ对象。

    查找BUFFER_OBJ对象的代码:

    PBUFFER_OBJ FindBufferObj(HANDLE hEvent){
        PBUFFER_OBJ pBuffer = g_pBufferHead;
        while(pBuffer != NULL){
            if(pBuffer->ol.hEvent == hEvent)
                break;
            pBuffer = pBuffer->pNext;
        }
        return pBuffer;
    }

    更新时间句柄数组g_events中的内容:

    void RebuildArray(){
        PBUFFER_OBJ pBuffer = g_pBufferHead;
        int i= 1;
        while(pBuffer != NULL){
            g_events[i++] = pBuffer->ol.hEvent;
            pBuffer = pBuffer->pNext;
        }
    }

    ---------------------3 提交重叠IO---------------------

    投递IO之后,线程在重叠IO事件上等待,一旦IO事件对象受信,等待函数就会返回

    提交接受连接的BUFFER_OBJ对象代码:

    BOOL PostAccept(PBUFFER_OBJ pBuffer){
        PSOCKET_OBJ pSocket = pBuffer->pSocket;
        if(pSocket->lpfnAcceptEx != NULL){
            //设置IO类型,增加套接字上的重叠IO计数
            pBuffer->nOperation = OP_ACCEPT;
            pSocket->nOutstandingOps++;
            //投递此重叠IO
            DWORD dwBytes;
            pBuffer->sAccept = ::WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
            BOOL b = pSocket->lpfnAcceptEx(
                pSocket->s,
                pBuffer->sAccept,
                pBuffer->buff,
                BUFFER_SIZE - ((sizeof(sockaddr_in+16))*2),
                sizeof(sockaddr_in)+16,
                sizeof(sockaddr_in)+16,
                &dwBytes,
                &pBuffer->ol
                );
            if(!b){
                if(::WSAGetLastError()!=WSA_IO_PENDING)
                    return FALSE;
            }
            return TRUE;
        }
        return FALSE;
    };

    接收数据的BUFFER_OBJ对象代码:

    BOOL PostRecv(PBUFFER_OBJ pBuffer){
        //设置IO类型,增加套接字上的重叠IO计数
        pBuffer->nOperation = OP_ACCEPT;
        pBuffer->pSocket->nOutstandingOps++;
        //投递此重叠IO
        DWORD dwBytes;
        DWORD dwFlags = 0;
        WSABUF buf;
        buf.buf = pBuffer->buff;
        buf.len = pBuffer->nLen;
        if(::WSARecv(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!=NO_ERROR){
            if(::WSAGetLastError()!= WSA_IO_PENDING)
                return FALSE;
        }
        return TRUE;
    }

    发送数据额BUFFER-obj对象代码:

    BOOL PostSend(PBUFFER_OBJ pBuffer){
        //设置IO类型,增加套接字上的重叠IO计数
        pBuffer->nOperation = OP_ACCEPT;
        pBuffer->pSocket->nOutstandingOps++;
        //投递此重叠IO
        DWORD dwBytes;
        DWORD dwFlags;
        WSABUF buf;
        buf.buf = pBuffer->buff;
        buf.len = pBuffer->nLen;
        if(::WSASend(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!=NO_ERROR){
            if(::WSAGetLastError()!=WSA_IO_PENDING)
                return FALSE;
        }
        return TRUE;
    }

    ---------------------4 主函数---------------------

  • 相关阅读:
    Hibernate中session的产生的方式
    Hibernate 多对多关联Demo
    Hibernate 一对多双向关联Demo
    Beta(0/7)
    获得小黄衫感想(2)
    软工实践作业(十)
    成员交换情况
    Alpha事后诸葛亮
    Alpha冲刺总结
    Alpha(10/10)
  • 原文地址:https://www.cnblogs.com/xing901022/p/2723439.html
Copyright © 2011-2022 走看看