完成端口实现echo tcp server

 
#include  < stdio.h >
#include 
< winsock2.h >
#pragma  comment(lib, "ws2_32.lib")


#define  PORT 5150
#define  DATA_BUFSIZE 8192
/*
 *无论何时调用重叠操作函数时,总是会通过其lpOverlapped参数传递一个OVERLAPPEDPLUS结构
 *(例如WSASend、 WSARecv等函数)。这就允许你为每一个重叠调用操作设置某些操作状态信息,
 *当操作结束后,你可以通过GetQueuedCompletionStatus()函数获得你自定义结构的指针。
 
*/
typedef 
struct   
{
    OVERLAPPED Overlapped;
    WSABUF     dataBuf;
    
char        buffer[DATA_BUFSIZE];
    
int         OpCode; // 传递操作码
}PER_IO_OPERATION_DATA,  * LPPER_IO_OPERATION_DATA;

#define  OP_READ   0
#define  OP_WRITE  1
#define  OP_ACCEPT 2

// 单句柄数据
typedef  struct   
{
    SOCKET Socket;
}PER_HANDLE_DATA,
*  LPPER_HANDLE_DATA;



DWORD WINAPI ServerWorkerThread(
void *  completionPortID);

int  main( int  argc,  char *  argv[])
{
    SOCKADDR_IN serverAddr;
    SOCKET listenSocket;
    SOCKET acceptSocket;
    HANDLE completionPort;
    WSADATA wsaData;
    
if (WSAStartup( 0x0202 & wsaData)  !=   0 )
    {
      printf(
" WSAStartup failed with error  " );
      
return   - 1 ;
    }
    
// 建立完成端口
     if ((completionPort  =  CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 , 0 ))  ==  NULL)
    {
        printf( 
" CreateIoCompletionPort failed with error: %d " , GetLastError());
        
return   - 1 ;
    }

    SYSTEM_INFO systemInfo;
    GetSystemInfo(
& systemInfo);
    DWORD threadID;

    
// 创建工作者线程
     for ( int  i  =   0 ; i  <  systemInfo.dwNumberOfProcessors * 2 ; i ++ )
    {
        HANDLE threadHandle;
        
if ((threadHandle  =  CreateThread(NULL, 0 ,ServerWorkerThread,completionPort, 0 , & threadID))  ==  NULL)
        {
            printf(
" CreateThread() failed with error %d " , GetLastError());
            
return   - 1 ;
        }
        CloseHandle(threadHandle);
    }
    

    
if  ((listenSocket  =  WSASocket(AF_INET, SOCK_STREAM,  0 , NULL,  0 ,
      WSA_FLAG_OVERLAPPED)) 
==  INVALID_SOCKET)
    {
      printf(
" WSASocket() failed with error %d " , WSAGetLastError());
      
return   - 1 ;
    } 


    serverAddr.sin_family 
=  AF_INET;
    serverAddr.sin_addr.s_addr 
=  htonl(INADDR_ANY);
    serverAddr.sin_port 
=  htons(PORT);

    
if (bind(listenSocket,(sockaddr * ) & serverAddr, sizeof (serverAddr))  ==  SOCKET_ERROR)
    {
        printf(
" bind() failed with error %d " , WSAGetLastError());
        
return   - 1 ;
    }

    
if  (listen(listenSocket,  10 ==  SOCKET_ERROR)
    {
      printf(
" listen() failed with error %d " , WSAGetLastError());
      
return   - 1 ;
    }
    
    
for (;;)
    {
        
        
if ((acceptSocket  =  WSAAccept(listenSocket,NULL,NULL,NULL, 0 ))  ==  SOCKET_ERROR)
        {
            printf(
" WSAAccept() failed with error %d " , WSAGetLastError());
            
return   - 1 ;
        }
    
        LPPER_HANDLE_DATA perHandleData 
=  (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,  sizeof (PER_HANDLE_DATA));
        printf(
" socket number %d connected " ,acceptSocket);
        perHandleData
-> Socket  =  acceptSocket;

        
// 新套接字句柄同完成端口关联到一起。
        
// 通过完成键(CompletionKey)参数,将单句柄数据结构传递给完成端口。
         if (CreateIoCompletionPort((HANDLE)acceptSocket,completionPort,(DWORD)perHandleData,
            
0 ==  NULL)
        {
            printf(
" CreateIoCompletionPort failed with error %d " , GetLastError());
            
return   - 1  ;
        }
        

        
// 为重叠调用建立单I/O操作数据
        LPPER_IO_OPERATION_DATA perIoData;
        perIoData 
=  (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof (PER_IO_OPERATION_DATA));
        memset(
& perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
        perIoData
-> dataBuf.len  =  DATA_BUFSIZE;
        perIoData
-> dataBuf.buf  =  perIoData -> buffer;
        perIoData
-> OpCode  =  OP_READ;  // 读操作

        
/*  开始在接受套接字上处理I/O
         * 使用重叠I/O机制,在新建的套接字上投递一个或多个异步
         * WSARecv 或 WSASend请求。这些I/O请求完成后,工作者线程
         * 会为I/O请求提供服务。
         
*/  
        DWORD recvBytes;
        DWORD flags 
=   0 ;
        WSARecv(acceptSocket,
                
& (perIoData -> dataBuf),
                
1 ,
                
& recvBytes,
                
& flags,
                
& (perIoData -> Overlapped),
                NULL);    
     }
    
    
return   0 ;
}


DWORD WINAPI ServerWorkerThread(
void *  completionPortID)
{
    HANDLE completionPort 
=  (HANDLE)completionPortID;
    DWORD bytesTransferred;
    
// LPOVERLAPPED Overlapped;
    LPPER_HANDLE_DATA perHandleData;
    LPPER_IO_OPERATION_DATA perIoData;
    
while ( true )
    {
        
if (GetQueuedCompletionStatus(completionPort, & bytesTransferred,
            (LPDWORD)
& perHandleData,(LPOVERLAPPED * ) & perIoData,INFINITE)  ==   0 )
        {
            printf(
" GetQueuedCompletionStatus failed with error %d " , GetLastError());
            
return   0 ;
        }
        
if (bytesTransferred  ==   0 )
        {
            printf(
" Closing socket %d " ,perHandleData -> Socket);
            closesocket(perHandleData
-> Socket);
            GlobalFree(perHandleData);
            GlobalFree(perIoData);
            
continue ;
        }

        
switch  (perIoData -> OpCode)    
        {   
        
case  OP_ACCEPT:       
                
break ;                   
        
case  OP_WRITE: // 写完成        
             {            
                
//  为下一个重叠调用建立单I/O操作数据
                memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
                perIoData
-> dataBuf.len  =  DATA_BUFSIZE;
                perIoData
-> dataBuf.buf  =  perIoData -> buffer;
                perIoData
-> OpCode  =  OP_READ;  // 读操作        
                DWORD recvBytes;
                DWORD flags 
=   0 ;
                WSARecv(perHandleData
-> Socket,
                    
& (perIoData -> dataBuf),
                    
1 ,
                    
& recvBytes,
                    
& flags,
                    
& (perIoData -> Overlapped),
                    NULL);    
                
break ;
            } 
        
case  OP_READ: // 读完成
            {    
                printf(
" recive socket %d :%s " ,perHandleData -> Socket,perIoData -> buffer);
                
// 为下一个重叠调用建立单I/O操作数据
                
// 将接收到的数据echo 回去
                memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
                perIoData
-> dataBuf.buf  =  perIoData -> buffer;
                perIoData
-> dataBuf.len  =  bytesTransferred;                
                perIoData
-> OpCode  =  OP_WRITE;  // 写操作        
                DWORD bytesSend;
                DWORD flags 
=   0 ;                            
                WSASend(perHandleData
-> Socket, & (perIoData -> dataBuf), 1 , & bytesSend,
                    
0 , & (perIoData -> Overlapped), 0 );                
                
break ;
            }        

        }
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值