重明鸟软件知识平台
@网络编程:IOCP(3)
我们写一个IOCP服务器,他的作用是把客户端的发送过来的信息回送过去。这个程序分为四个部份:

第一部分:定义传输数据的结构体。
#define BUF_SIZE 2048
//传输数据信息
struct IOCP_DATA
{
    OVERLAPPED overlapped;
    WSABUF dataBuf;
    char buf[BUF_SIZE];
    DWORD recvbytes;
    DWORD sendbytes;
};
//socket信息
struct IOCP_SOCKET
{
    SOCKET m_socket;
};


第二部分:服务器线程处理:

//服务器处理线程
DWORD WINAPI ServerThread(LPVOID CompletionPort)
{
    IOCP_SOCKET* m_Socket = NULL;
    IOCP_DATA* m_IocpData = NULL;
    DWORD m_BytesTransferred=0;
    DWORD Flags = 0;
    DWORD m_TransBytes = 0;
    HANDLE m_CompletionPort = CompletionPort;
    while(1)
    {
        if(GetQueuedCompletionStatus(m_CompletionPort,&m_BytesTransferred,
                (LPDWORD)&m_Socket,(LPOVERLAPPED*)&m_IocpData,INFINITE)==0)
        {
            printf("getQueued error!");
        }
   
        if(m_BytesTransferred == 0)
        {
            continue;
        }
   
        if(m_IocpData->recvbytes == 0)
        {
            //准备接收数据
            m_IocpData->recvbytes = m_BytesTransferred;
            m_IocpData->sendbytes = 0;
        }
        else
        {
            //准备发送数据
            m_IocpData->sendbytes += m_BytesTransferred;
        }
   
        //如果有数据没有发送,则发送出去
        if(m_IocpData->recvbytes > m_IocpData->sendbytes)
        {
            printf("send bytes...");
            ZeroMemory(&(m_IocpData->overlapped),sizeof(OVERLAPPED));
            //计算要发送字节数和起始地址
            m_IocpData->dataBuf.buf = m_IocpData->buf + m_IocpData->sendbytes;
            m_IocpData->dataBuf.len = m_IocpData->recvbytes - m_IocpData->sendbytes;
            if(WSASend(m_Socket->m_socket,&(m_IocpData->dataBuf),1,&m_TransBytes,0,
                        &(m_IocpData->overlapped),NULL)==SOCKET_ERROR)
            {
                printf("send bytes error!\n");
                return 0;
            }
        }
        else
        {
            //如果数据已经发送完,则等待接收新据
            printf("recv bytes...");
            m_IocpData->recvbytes = 0;
            ZeroMemory(&(m_IocpData->overlapped),sizeof(OVERLAPPED));
            m_IocpData->dataBuf.len = BUF_SIZE;
            m_IocpData->dataBuf.buf = m_IocpData->buf;
            if(WSARecv(m_Socket->m_socket,&(m_IocpData->dataBuf),1,&m_TransBytes,
            &Flags,&(m_IocpData->overlapped),NULL)==SOCKET_ERROR)
            {
                if(WSAGetLastError()!= ERROR_IO_PENDING)
                printf("thread recv error\n");
            }
        }
    }
    return 0;
}


第三部分:IOCP类

class NIOCP
{
public:
    SOCKET m_ServerSocket;
    HANDLE m_CompletionPort;
    int num_Cores;
private:
// 检查是否支持2.0
    bool TestVersion()
    {
        WSADATA wsaData;
        WORD version = MAKEWORD(2,0);
        //初始化WinSock DLL库
        int ret = WSAStartup(version,&wsaData);
        if(ret!=0)
            return false;
        return true;
    }
   
public:
    void CleanClient()
    {
        closesocket(m_ServerSocket);
        WSACleanup();
    }
   
    int GetNumCore()
    {
        SYSTEM_INFO SystemInfo;
        GetSystemInfo(&SystemInfo);
        num_Cores = SystemInfo.dwNumberOfProcessors;
        return num_Cores;
    }
   
    bool InitIOCP()
    {
        IOCP_SOCKET* m_HandleSocket;
        IOCP_DATA* m_IocpData;
        if(TestVersion()==false)
        {
            printf("require WSA 2.0");
        }
   
        //创建完成端口
        m_CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
        if(m_CompletionPort==NULL)
        {
            printf("create completionport error");
        }
        DWORD threadID=0;
        //创建服务端处理线程
        int n=0;
        for(n=0;n<num_Cores;n++)
        {
            HANDLE threadHandle;
            threadHandle = CreateThread(NULL,0,ServerThread,
            m_CompletionPort,0,&threadID);
   
            if(threadHandle==NULL)
            {
                printf("create thread error!");
            }
   
            CloseHandle(threadHandle);
        }
            //创建服务端socket
        m_ServerSocket = WSASocket(AF_INET,SOCK_STREAM,0,
            NULL,0,WSA_FLAG_OVERLAPPED);
   
        if(m_ServerSocket == INVALID_SOCKET)
        {
            printf("Init Socket error!");
        }
   
        //初始化socket的网络地址
        sockaddr_in m_addr;
        m_addr.sin_family = AF_INET;
        m_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        m_addr.sin_port = htons(10001);
        bind(m_ServerSocket,(PSOCKADDR)&m_addr,sizeof(m_addr));
        listen(m_ServerSocket,10);
        SOCKET m_TempSocket;
   
        while(true)
        {
            struct sockaddr_in client_address;
            int address_len = sizeof(client_address);
            //捕获申请链接的socket
            m_TempSocket = WSAAccept(m_ServerSocket,
                (struct sockaddr*)(&client_address),&address_len,NULL,0);
   
            printf("client IP:%s connected!\n",inet_ntoa(client_address.sin_addr));
            //给数据分配空间,并加入完成端口队列
            m_HandleSocket = (IOCP_SOCKET*)GlobalAlloc(GPTR,sizeof(IOCP_SOCKET));
            m_HandleSocket->m_socket = m_TempSocket;
            if(CreateIoCompletionPort((HANDLE)m_TempSocket,m_CompletionPort,
                     (DWORD)m_HandleSocket,0)==NULL)
            {
                printf("create iocp error!\n");
                return false;
            }
   
            m_IocpData = (IOCP_DATA*)GlobalAlloc(GPTR,sizeof(IOCP_DATA));
            ZeroMemory(&(m_IocpData->overlapped),sizeof(OVERLAPPED));
            m_IocpData->sendbytes = 0;
            m_IocpData->recvbytes = 0;
            m_IocpData->dataBuf.len = BUF_SIZE;
            m_IocpData->dataBuf.buf = m_IocpData->buf;
            DWORD Flag = 0;
            DWORD TransBytes = 0;
   
            if(WSARecv(m_TempSocket,&(m_IocpData->dataBuf),1,&TransBytes,
            &Flag,&(m_IocpData->overlapped),NULL)==SOCKET_ERROR)
            {
                if(WSAGetLastError()!= ERROR_IO_PENDING)
                    printf("recv error\n");
            }
        }
        return true;
    }
};


第四部分:主程序调用

int main()
{
    NIOCP* S_IOCP=new NIOCP;
    printf("CPU CORES:%d\n",S_IOCP->GetNumCore());
   
    if(false==S_IOCP->InitIOCP())
    {
        printf("Init IOCP error!\n");
    }
   
    getch();
    return 0;
}


以上四部份代码都写到一个CPP里面,当然你也可以分开几个CPP来写。运行结果是一样的。
最后我们启动第一节中TCP的客户端程序来检验一下服务器程序。

IOCP服务程序
CPU CORES:4
client IP:192.168.1.100 connected!
send bytes...
recv bytes...

客户端我们用之前TCP的客户程序
connect 192.168.1.99:10001 ok
recv:Hello

可以看到,当客户发送链接申请给服务器,并传送数据给服务器后,服务线程将信息回发给客户,然后就继续等待接收新的数据传入。
@站内查找
@栏目文章
【基础教程】Python守护进程创建
【基础教程】PyGame(13):三维环境设置
【基础教程】C/C++指针函数和回调函数
【基础教程】C/C++多进程编程(3)
【基础教程】C/C++多进程编程(2)
【基础教程】C/C++多进程编程(1)
【基础教程】C/C++多线程编程(2)
【基础教程】C/C++多线程编程(1)
【基础教程】C/C++动态库编程
【基础教程】C/C++静态库编程
【基础教程】photoshop图片混合公式
【基础教程】PyGame(12):旋转和缩放
【基础教程】PyGame(11):Surface操作
【基础教程】网络编程:Epoll(2)
【基础教程】网络编程:Epoll(1)
【基础教程】网络编程:IOCP(3)
【基础教程】网络编程:IOCP(2)
【基础教程】网络编程:IOCP(1)
【基础教程】网络编程:UDP
【基础教程】网络编程:TCP
【基础教程】Ubuntu安装Hadoop(4)
【基础教程】Ubuntu安装Hadoop(3)
【基础教程】Ubuntu安装Hadoop(2)
【基础教程】Ubuntu安装Hadoop(1)
【基础教程】Hadoop技术原理
【基础教程】Hadoop基本命令
【基础教程】Hadoop是什么东西
【基础教程】排序算法介绍
【基础教程】PyGame(10):声音控制
【基础教程】PyGame(9):鼠标事件(2)
【基础教程】PyGame(8):鼠标事件(1)
【基础教程】PyGame(7):键盘事件(2)
【基础教程】PyGame(6):键盘事件(1)
【基础教程】PyGame(5):显示图片
【基础教程】PyGame(4):显示文字
【基础教程】PyGame(3):图元绘制
【基础教程】PyGame(2):游戏框架
【基础教程】PyGame(1):开发环境搭建
【基础教程】Python(10):类定义
【基础教程】Python(9):自定义模块
【基础教程】Python(8):输入输出控制
【基础教程】Python(7):函数定义
【基础教程】Python(6):中断语句
【基础教程】Python(5):判断语句
【基础教程】Python(4):循环语句
【基础教程】Python(3):变量与运算符
【基础教程】Python(2):Hello
【基础教程】Python(1):介绍与安装
Copyright @ 2011-2018 by szc  桂ICP备11003301号-1  桂公网安备45040302000027号  Email:szcsoft@qq.com