Windows Socket I/O模型之 Select模式

# include < winsock2. h>
# include < ws2tcpip. h>

# include "resolve.h"
# include "public.h"

typedef SINGLE_LIST_HEADER BuffHeader;
typedef SINGLE_LIST BuffObj;
typedef DOUBLE_LIST_HEADER SockObjHeader;
typedef DOUBLE_LIST SockObj;

typedef struct _SOCKET_OBJ
{
    SOCKET s; // Socket handle

    int listening; // Socket is a listening socket (TCP)

    int closing; // Indicates whether the connection is closing


    SOCKADDR_STORAGE addr; // Used for client's remote address

    int addrlen; // Length of the address


    BuffHeader buff;

    DOUBLE_LIST entry;
} SOCKET_OBJ;

SockObjHeader sockobjhead;

SOCKET_OBJ* GetSocketObj( SOCKET s, int listening) {
    SOCKET_OBJ * sockobj = NULL ;

    sockobj = ( SOCKET_OBJ* ) HeapAlloc( GetProcessHeap( ) , HEAP_ZERO_MEMORY, sizeof ( SOCKET_OBJ) ) ;
    if ( sockobj = = NULL ) {
        fprintf ( stderr , "HeapAlloc failed./n" ) ;
        ExitProcess( - 1) ;
    }

    sockobj- > s = s;
    sockobj- > listening = listening;
    sockobj- > addrlen = sizeof ( sockobj- > addr) ;

    InitializeCriticalSection( & sockobj- > buff. SendRecvQueueCritSec) ;

    return sockobj;
}

void FreeSocketObj( SOCKET_OBJ * obj) {
    BuffObj * ptr = NULL ;
    BUFFER_OBJ * blk = NULL ;

    while ( true ) {
        ptr = DequeueSingleList( & obj- > buff) ;
        if ( ptr = = NULL )
            break ;

        blk = ( BUFFER_OBJ * ) container_of( BUFFER_OBJ, next, ptr) ;
        FreeBufferObj( blk) ;
    }

    HeapFree( GetProcessHeap( ) , 0, obj) ;
}

int ReceivePendingData( SOCKET_OBJ * obj) {
    BUFFER_OBJ * buffobj = NULL ;
    int rc, ret;

    buffobj = GetBufferObj( gBufferSize) ;
    ret = 0;

    if ( gProtocol = = IPPROTO_TCP ) {
        rc = recv ( obj- > s, buffobj- > buf, buffobj- > buflen, 0) ;
    } else {
        ExitProcess( - 1) ;
    }

    if ( rc = = SOCKET_ERROR) {
        ExitProcess( - 1) ;
    } else if ( rc = = 0) {
        FreeBufferObj( buffobj) ;
        obj- > closing = TRUE ;

        if ( obj- > buff. head = = NULL ) {
            closesocket( obj- > s) ;
            ret = - 1;
        }
    } else {
        buffobj- > buflen = rc;
        EnqueueSingleList( & obj- > buff, & buffobj- > next) ;
    }
    return ret;
}

int SendPendingData( SOCKET_OBJ * sock) {
    BUFFER_OBJ * bufobj = NULL ;
    BuffObj * entry = NULL ;
    int nleft = 0,
                idx = 0,
                ret = 0,
                rc = 0;

    while ( entry = DequeueSingleList( & sock- > buff) ) {
        bufobj = ( BUFFER_OBJ * ) container_of( BUFFER_OBJ, next, entry) ;

        if ( gProtocol = = IPPROTO_TCP ) {
            nleft = bufobj- > buflen;
            idx = 0;

            while ( nleft > 0) {
                rc = send ( sock- > s, & ( bufobj- > buf[ idx] ) , nleft, 0) ;
                if ( rc = = SOCKET_ERROR) {
                    ExitProcess( - 1) ;
                } else {
                    idx + = rc;
                    nleft - = rc;
                }
            }

            FreeBufferObj( bufobj) ;
        } else {
            ExitProcess( - 1) ;
        }
    }

    if ( sock- > closing = = TRUE ) {
        closesocket( sock- > s) ;
        ret = - 1;

        printf ( "Closing Connection./n" ) ;
    }

    return ret;
}

int _tmain( int argc, _TCHAR* argv[ ] )
{
    WSADATA wsd;

    SOCKET s;

    struct addrinfo * res = NULL ;
    struct addrinfo * ptr = NULL ;

    SOCKET_OBJ * sockobj = NULL ;

    int rc;

    struct fd_set fdread, fdwrite, fdexcept;
    struct timeval timeout;

    if ( WSAStartup( MAKEWORD( 2, 2) , & wsd) ! = 0) {
        fprintf ( stderr , "load winsock2 failed./n" ) ;
        return 0;
    }

    res = ResolveAddress( gSrvAddr, gPort, gAddressFamily, gSocketType, gProtocol) ;
    if ( res = = NULL ) {
        fprintf ( stderr , "resolve addr failed./n" ) ;
        return - 1;
    }

    InitializeDoubleHead( & sockobjhead) ;

    ptr = res;
    while ( ptr) {
        s = socket ( ptr- > ai_family, ptr- > ai_socktype, ptr- > ai_protocol) ;
        if ( s = = INVALID_SOCKET) {
            fprintf ( stderr , "create socket failed./n" ) ;
            break ;
        }

        sockobj = GetSocketObj( s, ( gProtocol = = IPPROTO_TCP ) ? TRUE : FALSE ) ;
        EnqueueDoubleList( & sockobjhead, & sockobj- > entry) ;

        rc = bind ( sockobj- > s, ptr- > ai_addr, ptr- > ai_addrlen) ;
        if ( rc = = SOCKET_ERROR) {
            fprintf ( stderr , "bind failed./n" ) ;
            return 0;
        }

        if ( gProtocol = = IPPROTO_TCP )
        {
            rc = listen ( sockobj- > s, 200) ;
            if ( rc = = SOCKET_ERROR)
            {
                fprintf ( stderr , "listen failed: %d/n" , WSAGetLastError( ) ) ;
                return - 1;
            }
        }

        ptr = ptr- > ai_next;
    }

    freeaddrinfo ( res) ;

    while ( true ) {
        FD_ZERO( & fdread) ;
        FD_ZERO( & fdwrite) ;
        FD_ZERO( & fdexcept) ;

        SockObj * sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, & ( sockobjhead. head) ) ;
        SOCKET_OBJ * obj = NULL ;
        while ( sptr) {
            obj = ( SOCKET_OBJ * ) container_of( SOCKET_OBJ, entry, sptr) ;

            FD_SET( obj- > s, & fdread) ;
            FD_SET( obj- > s, & fdwrite) ;
            FD_SET( obj- > s, & fdexcept) ;

            sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
        }

        timeout. tv_sec = 5;
        timeout. tv_usec = 0;

        rc = select ( 0, & fdread, & fdwrite, & fdexcept, & timeout) ;
        if ( rc = = SOCKET_ERROR) {
            fprintf ( stderr , "select failed./n" ) ;
            return - 1;
        } else if ( rc = = 0) {
            printf ( "Wait Time out./n" ) ;
            continue ;
        }

        sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, & ( sockobjhead. head) ) ;
        SockObj * tmp = NULL ;
        obj = NULL ;
        while ( sptr) {
            obj = ( SOCKET_OBJ * ) container_of( SOCKET_OBJ, entry, sptr) ;

            if ( FD_ISSET( obj- > s, & fdread) ) {
                if ( obj- > listening) {
                    sockobj = ( SOCKET_OBJ * ) GetSocketObj( INVALID_SOCKET, FALSE ) ;

                    s = accept ( obj- > s, ( SOCKADDR * ) & sockobj- > addr, & sockobj- > addrlen) ;
                    if ( s = = INVALID_SOCKET) {
                        fprintf ( stderr , "accept failed./n" ) ;
                        return - 1;
                    }
                    sockobj- > s = s;

                    EnqueueDoubleListHead( & sockobjhead, & sockobj- > entry) ;
                } else {
                    if ( ReceivePendingData( obj) ! = 0) {
                        printf ( "ReceivePendingData./n" ) ;

                        tmp = sptr;
                        sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
                        RemoveDoubleList( & sockobjhead, tmp) ;
                        FreeSocketObj( obj) ;

                        continue ;
                    }

                    if ( SendPendingData( obj) ! = 0) {
                        tmp = sptr;
                        sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
                        RemoveDoubleList( & sockobjhead, tmp) ;
                        FreeSocketObj( obj) ;

                        continue ;
                    }
                }
            }
            if ( FD_ISSET( obj- > s, & fdwrite) ) {
                if ( SendPendingData( obj) ! = 0) {
                    tmp = sptr;
                    sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
                    RemoveDoubleList( & sockobjhead, tmp) ;
                    FreeSocketObj( obj) ;

                    continue ;
                }
            }
            if ( FD_ISSET( obj- > s, & fdexcept) ) {
                tmp = sptr;
                sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
                RemoveDoubleList( & sockobjhead, tmp) ;
                FreeSocketObj( obj) ;
            }

            sptr = ( SockObj * ) GotoNextDoubleList( & sockobjhead, sptr) ;
        }
    }

    WSACleanup( ) ;

    return 0;
}

 

版权声明: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。

猜你喜欢

转载自blog.csdn.net/micklongen/article/details/6171923