Windows网络编程示例二——反应式echo服务器

代码组织上不是很合理,很多细节没有注意,只是作为一个演示记下反应式I/O的一种使用模式,通过telnet作为客户端演示之。
/**
 * 基于反应式I/O的echo服务器。监听端口5432,CTRL+C优雅结束服务。
 * 
 *
 * 完成:
 * 1)通过单线程为多个客户提供服务。
 * 2)通过信号机制优雅的结束服务。
 * 3)减少fd_set的构建。
 * 4)避免资源泄露。
 *
 * 未完成:
 * 1)链接数受系统限制。
 * 2)错误处理不一致。
 
*/


//#include 
<vld.h>

#include 
< assert.h >
#include 
< signal.h >

#include 
< iostream >
#include 
< list >
using   namespace  std;


#ifdef WIN32
/// 去掉下面注释,更改其默认值
#define  FD_SETSIZE 1024
#   include 
< WinSock2.h >
#   pragma comment(lib, 
" ws2_32.lib " )
#   include 
< mswsock.h >
#   pragma comment(lib, 
" Mswsock.lib " )
#   define PRINT_SOCKET_ERROR(FUNC) 
    
do  
    

    cout 
<< "<" << #FUNC << "> Call Error!" << " " 
    
<< "Error Number : " << WSAGetLastError() << endl; 
    }
  while ( 0 )

#endif   //  WIN32

#define  PORT 5432

//  = 类型定义
struct  Connection
{
    
enum {BufSize = 1024 * 4};

    Connection(SOCKET fd)
        : mFd(fd)
        , mReadPos(
0)
        , mWritePos(
0)
    
{
    }

    SOCKET mFd;
    
int mReadPos;
    
int mWritePos;
    
char mBuffer[BufSize];   
}
;

struct  FdSets
{
    fd_set mRead;
    fd_set mWrite;
    fd_set mException;
}
;

typedef list
< Connection *>  ConnectionRepository;
typedef ConnectionRepository::iterator ConnectionRepositoryIterator;

//  = 全局数据
ConnectionRepository gConnRep;
/// 
FdSets gFdSets;
/// 
SOCKET gReadPipe;
SOCKET gWritePipe;
BOOL gIsShutDown 
=  FALSE;

//  = 
int  createListenFd(SOCKADDR_IN  & addr, SOCKET  & fd)
{
    
int nRet = 0;
    
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        PRINT_SOCKET_ERROR(socket);
        
return -1;
    }

    
if ((nRet = bind(fd, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN))) != 0{
        PRINT_SOCKET_ERROR(bind);
        
return nRet;
    }

    
if ((nRet = listen(fd, 5)) != 0{
        PRINT_SOCKET_ERROR(listen);
        
return nRet;
    }

    
else {
        cout 
<< "Listening at " << inet_ntoa(addr.sin_addr) 
            
<< ":" << ntohs(addr.sin_port) << endl;
    }

    
return nRet;
}


int  createPipe( void )
{
    
int nRet = 0;
    SOCKADDR_IN addr;
    
int addr_size = sizeof(SOCKADDR_IN);
    addr.sin_family 
= AF_INET;
    addr.sin_port 
= htons(0);
    addr.sin_addr.s_addr 
= htonl(INADDR_LOOPBACK);
    
    SOCKET fd;
    
if(createListenFd(addr, fd) != 0)
        
goto error_return;
    
if (getsockname(fd, (PSOCKADDR)&addr, &addr_size) != 0)
        
goto error_return;
    
if ((gWritePipe = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) 
        
== INVALID_SOCKET)
        
goto error_return;

    
if (connect(gWritePipe, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN)) != 0)
        
goto error_return;
    
if ((gReadPipe = accept(fd, 00)) == INVALID_SOCKET)
        
goto error_return;

    FD_SET(gReadPipe, 
&gFdSets.mRead);
    closesocket(fd);

    
return 0;

error_return:
    
return -1;
}


void  performRead(fd_set  & set )
{
    
if (set.fd_count == 0)
        
return;

    ConnectionRepositoryIterator it 
= gConnRep.begin();
    ConnectionRepositoryIterator end 
= gConnRep.end();
    
int read_bytes = 0;
    
for ( ;it != end; )//++it)
    {
        Connection 
*conn = *it;
        
if (FD_ISSET(conn->mFd, &set))
        
{
            read_bytes 
= recv(conn->mFd, conn->mBuffer + conn->mReadPos, 
                              Connection::BufSize, 
0);
            
if (read_bytes > 0)
            

                
/// !!!NOTE
                conn->mReadPos += read_bytes;
                FD_SET(conn
->mFd, &gFdSets.mWrite); 
            }

            
else
            
{
                
if (read_bytes == 0)
                    cout 
<< conn->mFd << " Closed!" << endl;
                
else
                    cout 
<< conn->mFd << " recv Error!Error code:" << WSAGetLastError() << endl;

                it 
= gConnRep.erase(it);
                FD_CLR(conn
->mFd, &gFdSets.mRead);
                closesocket(conn
->mFd);
                delete conn;
                
continue;
            }

        }

        
++it;
    }

}


void  performWrite(fd_set  & set )
{
    
if (set.fd_count == 0)
        
return;

    ConnectionRepositoryIterator it 
= gConnRep.begin();
    ConnectionRepositoryIterator end 
= gConnRep.end();
    
int send_bytes = 0;
    
for ( ;it != end; )
    
{
        Connection 
*conn = *it;
        
if (FD_ISSET(conn->mFd, &set))
        
{
            
int len = conn->mReadPos - conn->mWritePos;
            
            assert(len 
> 0);

            send_bytes 
= send(conn->mFd, conn->mBuffer + conn->mWritePos, len, 0);
            
if (send_bytes == len)
            
{
                conn
->mWritePos = conn->mReadPos = 0;
                FD_CLR(conn
->mFd, &gFdSets.mWrite);
            }

            
else if (send_bytes > 0)
            
{
                cout 
<< "Not send all data out!!!" << endl;
                conn
->mWritePos += send_bytes;
            }

            
else
            
{
                
/// !!!NOTE
                cout << "FD:" << conn->mFd << " send data error!" << endl;
                it 
= gConnRep.erase(it);
                FD_CLR(conn
->mFd, &gFdSets.mRead);
                FD_CLR(conn
->mFd, &gFdSets.mWrite);
                closesocket(conn
->mFd);
                delete conn;
                
continue;
            }

        }

        
++it;
    }

}


void  perfromException(fd_set  & set )
{
}


void  signal_handler( int  signum)
{
    
char buffer[] = "c";
    
int c = send(gWritePipe, buffer, 20);
}


class  Initializer
{
public:
    Initializer() 
{
        WSAData wsaData;
        mRet 
= WSAStartup(0x0202&wsaData);

        
if (mRet == 0)
            mRet 
= createPipe();

        signal(SIGINT, signal_handler);
    }

    
~Initializer() {
        closesocket(gReadPipe);
        closesocket(gWritePipe);
        mRet 
= WSACleanup();
    }

    
int Ret(voidconst {
        
return mRet;
    }

private:
    
int mRet;
}
;

int  main( int  argc,  char   * argv[])
{
    
// = 初始化
    Initializer iws2;
    
int nRet = iws2.Ret();

    
if (nRet != 0)
        
return -1;
    
    
// = 设置监听socket句柄
    SOCKET fdListen;
    SOCKADDR_IN hostAddr; 
    
{
        hostAddr.sin_family 
= AF_INET;
        hostAddr.sin_port 
= htons(PORT);
        hostAddr.sin_addr.s_addr 
= htonl(INADDR_ANY);
    }
    
    createListenFd(hostAddr, fdListen);
    FD_SET(fdListen, 
&gFdSets.mRead);

    
// =
    SOCKET fdAccepted;
    
int n;
    
while (1)
    
{
        FdSets dispatchSets;
        memcpy(
&dispatchSets, &gFdSets, sizeof(FdSets));
        
if ((n = select(0,  &dispatchSets.mRead,
            
&dispatchSets.mWrite, &dispatchSets.mException, NULL)) == SOCKET_ERROR)
        
{
            PRINT_SOCKET_ERROR(select);
            
break;
        }

        
        
if (FD_ISSET(gReadPipe, &dispatchSets.mRead))
        
{
            
char buf[32];
            recv(gReadPipe, buf, 
320);
            ConnectionRepositoryIterator end 
= gConnRep.end();
            
for (ConnectionRepositoryIterator it = gConnRep.begin();
                it 
!= end; ++it)
            
{
                Connection
* conn = *it;
                
if (shutdown(conn->mFd, SD_SEND)!= 0)
                    cout 
<< "fd[" << conn->mFd << "] shutdown error!!!" << endl;
            }

            gIsShutDown 
= TRUE;
        }

        
if (FD_ISSET(fdListen, &dispatchSets.mRead))
        
{
            SOCKADDR_IN remoteAddr;
            
int remote_addr_size = sizeof(SOCKADDR_IN);
            
if ((fdAccepted = accept(fdListen,
                (PSOCKADDR)
&remoteAddr, &remote_addr_size)) == INVALID_SOCKET)
            
{
                PRINT_SOCKET_ERROR(accept);
                
break;
            }

            FD_SET(fdAccepted, 
&gFdSets.mRead);
            Connection
* conn = new Connection(fdAccepted);
            gConnRep.push_back(conn);
            
//continue;
        }

        performWrite(dispatchSets.mWrite);
        performRead(dispatchSets.mRead);        
        perfromException(dispatchSets.mException);

        
if (gIsShutDown && gConnRep.empty())
            
break;
    }


    closesocket(fdListen);

    
return 0;
}
;
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值