Windows Socket IO模型之 IO完成端口

    技术2024-08-17  64

    # include < winsock2. h> # include < ws2tcpip. h># include < mswsock. h># include < windows. h> # include "resolve.h"# include "public.h" # define DEFAULT_OVERLAPPED_COUNT 5# define MAX_COMPLETION_THREAD_COUNT 32 // Maximum number of completion threads allowed typedef SINGLE_LIST_HEADER SocketObjHeader;typedef SINGLE_LIST SocketObj;typedef DOUBLE_LIST_HEADER BufferObjHeader;typedef DOUBLE_LIST BufferObj; int gOverlappedCount = DEFAULT_OVERLAPPED_COUNT; typedef struct _BUFFER_OBJ_EX {    WSAOVERLAPPED ol; // Overlapped structure     SOCKET sclient; // Used for AcceptEx client socket     char * buf; // Buffer for send/recv/AcceptEx    int buflen; // Length of the buffer     int operation; // Type of operation submitted# define OP_ACCEPT 0 // AcceptEx# define OP_READ 1 // WSARecv/WSARecvFrom# define OP_WRITE 2 // WSASend?WSASendTo     SOCKADDR_STORAGE addr; // Remote address (UDP)    int addrlen; // Remote address length     ULONG IoOrder; // Order in which this I/O was posted     BufferObj bufDList;} BUFFER_OBJ_EX; typedef struct _SOCKET_OBJ{    SOCKET s; // Socket handle for client connection     int af, // Address family of socket (AF_INET or AF_INET6)                         bClosing; // Indicates socket is closing     volatile LONG OutstandingOps; // Number of outstanding overlapped ops     BUFFER_OBJ_EX * * PendingAccepts; // Array of pending AcceptEx calls (listening socket only)     ULONG LastSendIssued, // Last sequence number sent                         IoCountIssued; // Next sequence number assigned to receives    BufferObjHeader OutOfOrderSends; // List of send buffers that completed out of order     // Pointers to Microsoft specific extensions (listening socket only)    LPFN_ACCEPTEX lpfnAcceptEx;    LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs;     CRITICAL_SECTION SockCritSec; // Synchronize access to this SOCKET_OBJ     SocketObj next; // Used to chain SOCKET_OBJ together} SOCKET_OBJ; SOCKET_OBJ * GetSocketObj( SOCKET s, int af){    SOCKET_OBJ * sockobj= NULL ;     sockobj = ( SOCKET_OBJ * ) HeapAlloc( GetProcessHeap( ) , HEAP_ZERO_MEMORY, sizeof ( SOCKET_OBJ) ) ;    if ( sockobj = = NULL )    {        fprintf ( stderr , "GetSocketObj: HeapAlloc failed: %d/n" , GetLastError( ) ) ;        ExitProcess( - 1) ;    }     InitializeCriticalSection( & sockobj- > SockCritSec) ;    InitializeDoubleHead( & sockobj- > OutOfOrderSends) ;     sockobj- > IoCountIssued = ( ( gProtocol = = IPPROTO_TCP ) ? 1 : 0) ;     // Initialize the members    sockobj- > s = s;    sockobj- > af = af;     return sockobj;} BUFFER_OBJ_EX * GetBufferObjEx( int buflen){    BUFFER_OBJ_EX * newobj= NULL ;     // Allocate the object    newobj = ( BUFFER_OBJ_EX * ) HeapAlloc( GetProcessHeap( ) , HEAP_ZERO_MEMORY, sizeof ( BUFFER_OBJ_EX) ) ;    if ( newobj = = NULL ) {        printf ( "GetBufferObj: HeapAlloc failed: %d/n" , GetLastError( ) ) ;        ExitProcess( - 1) ;    }     // Allocate the buffer    newobj- > buf = ( char * ) HeapAlloc( GetProcessHeap( ) , HEAP_ZERO_MEMORY, sizeof ( BYTE) * buflen) ;    if ( newobj- > buf = = NULL ) {        printf ( "GetBufferObj: HeapAlloc failed: %d/n" , GetLastError( ) ) ;        ExitProcess( - 1) ;    }     newobj- > buflen = buflen;    newobj- > addrlen = sizeof ( newobj- > addr) ;     return newobj;} void FreeBufferObjEx( BUFFER_OBJ_EX * obj){    HeapFree( GetProcessHeap( ) , 0, obj- > buf) ;    HeapFree( GetProcessHeap( ) , 0, obj) ;} void FreeSocketObj( SOCKET_OBJ * obj){    BUFFER_OBJ_EX * ptr= NULL ,                * tmp= NULL ;     if ( obj- > OutstandingOps ! = 0)    {        // Still outstanding operations so just return        return ;    }    // Close the socket if it hasn't already been closed    if ( obj- > s ! = INVALID_SOCKET)    {        closesocket( obj- > s) ;        obj- > s = INVALID_SOCKET;    }     DeleteCriticalSection( & obj- > SockCritSec) ;     HeapFree( GetProcessHeap( ) , 0, obj) ;} void InsertPendingSend( SOCKET_OBJ * sock, BUFFER_OBJ_EX * send ){    BufferObj * ptr = NULL ;    BUFFER_OBJ_EX * obj = NULL ;     EnterCriticalSection( & sock- > SockCritSec) ;     ptr = ( BufferObj * ) GotoNextDoubleList( & sock- > OutOfOrderSends, & sock- > OutOfOrderSends. head) ;    while ( ptr)    {        obj = ( BUFFER_OBJ_EX * ) container_of( BUFFER_OBJ_EX, bufDList, ptr) ;        if ( send - > IoOrder < obj- > IoOrder)        {            break ;        }         ptr = ( BufferObj * ) GotoNextDoubleList( & sock- > OutOfOrderSends, ptr) ;    }    if ( ptr = = NULL )        ptr = & sock- > OutOfOrderSends. head;     EnqueueDoubleListBefore( & sock- > OutOfOrderSends, ptr, & send - > bufDList) ;     LeaveCriticalSection( & sock- > SockCritSec) ;} int PostRecv( SOCKET_OBJ * sock, BUFFER_OBJ_EX * recvobj){    WSABUF wbuf;    DWORD bytes,            flags;    int rc;      recvobj- > operation = OP_READ;     wbuf. buf = recvobj- > buf;    wbuf. len = recvobj- > buflen;     flags = 0;     EnterCriticalSection( & sock- > SockCritSec) ;     // Assign the IO order to this receive. This must be performned within    // the critical section. The operation of assigning the IO count and posting    // the receive cannot be interupted.    recvobj- > IoOrder = sock- > IoCountIssued;    sock- > IoCountIssued+ + ;     if ( gProtocol = = IPPROTO_TCP )    {        rc = WSARecv(                sock- > s,               & wbuf,                1,               & bytes,               & flags,               & recvobj- > ol,                NULL                ) ;    }    else    {        ExitProcess( - 1) ;    }     LeaveCriticalSection( & sock- > SockCritSec) ;     if ( rc = = SOCKET_ERROR)    {        if ( WSAGetLastError( ) ! = WSA_IO_PENDING)        {            fprintf ( stderr , "PostRecv: WSARecv* failed: %d/n" , WSAGetLastError( ) ) ;            return SOCKET_ERROR;        }    }     // Increment outstanding overlapped operations    InterlockedIncrement( & sock- > OutstandingOps) ;     return NO_ERROR;} int sendnum = 0; int PostSend( SOCKET_OBJ * sock, BUFFER_OBJ_EX * sendobj){    WSABUF wbuf;    DWORD bytes;    int rc;     sendobj- > operation = OP_WRITE;     wbuf. buf = sendobj- > buf;    wbuf. len = sendobj- > buflen;     EnterCriticalSection( & sock- > SockCritSec) ;     // Incrmenting the last send issued and issuing the send should not be    // interuptable.    sock- > LastSendIssued+ + ;     if ( gProtocol = = IPPROTO_TCP )    {        printf ( "send %d/n" , sendnum+ + ) ;        rc = WSASend(                sock- > s,               & wbuf,                1,               & bytes,                0,               & sendobj- > ol,                NULL                ) ;    }    else {        ExitProcess( - 1) ;    }     LeaveCriticalSection( & sock- > SockCritSec) ;     if ( rc = = SOCKET_ERROR)    {        if ( WSAGetLastError( ) ! = WSA_IO_PENDING)        {            fprintf ( stderr , "PostSend: WSASend* failed: %d/n" , WSAGetLastError( ) ) ;            return SOCKET_ERROR;        }    }     // Increment the outstanding operation count    InterlockedIncrement( & sock- > OutstandingOps) ;     return NO_ERROR;} int PostAccept( SOCKET_OBJ * sock, BUFFER_OBJ_EX * acceptobj){    DWORD bytes;    int rc;     acceptobj- > operation = OP_ACCEPT;     // Create the client socket for an incoming connection    acceptobj- > sclient = socket ( sock- > af, SOCK_STREAM , IPPROTO_TCP ) ;    if ( acceptobj- > sclient = = INVALID_SOCKET)    {        fprintf ( stderr , "PostAccept: socket failed: %d/n" , WSAGetLastError( ) ) ;        return - 1;    }     rc = sock- > lpfnAcceptEx(            sock- > s,            acceptobj- > sclient,            acceptobj- > buf,            acceptobj- > buflen - ( ( sizeof ( SOCKADDR_STORAGE) + 16) * 2) ,            sizeof ( SOCKADDR_STORAGE) + 16,            sizeof ( SOCKADDR_STORAGE) + 16,           & bytes,           & acceptobj- > ol            ) ;    if ( rc = = FALSE )    {        if ( WSAGetLastError( ) ! = WSA_IO_PENDING)        {            fprintf ( stderr , "PostAccept: AcceptEx failed: %d/n" , WSAGetLastError( ) ) ;            return SOCKET_ERROR;        }    }     // Increment the outstanding overlapped count for this socket    InterlockedIncrement( & sock- > OutstandingOps) ;     return NO_ERROR;} int DoSends( SOCKET_OBJ * sock){    BufferObj * ptr = NULL ;    BufferObj * tmp = NULL ;    BUFFER_OBJ_EX * sendobj = NULL ;     int ret;     ret = NO_ERROR;     EnterCriticalSection( & sock- > SockCritSec) ;     ptr = ( BufferObj * ) GotoNextDoubleList( & sock- > OutOfOrderSends, & sock- > OutOfOrderSends. head) ;    while ( ptr) {        sendobj = ( BUFFER_OBJ_EX * ) container_of( BUFFER_OBJ_EX, bufDList, ptr) ;        if ( ( sendobj) & & ( sendobj- > IoOrder = = sock- > LastSendIssued) )        {            if ( PostSend( sock, sendobj) ! = NO_ERROR)            {                FreeBufferObjEx( sendobj) ;                    ret = SOCKET_ERROR;                break ;            }        } else            break ;        tmp = ptr;        ptr = ( BufferObj * ) GotoNextDoubleList( & sock- > OutOfOrderSends, ptr) ;         RemoveDoubleList( & sock- > OutOfOrderSends, tmp) ;        //FreeBufferObjEx(sendobj);    }     LeaveCriticalSection( & sock- > SockCritSec) ;     return ret;} int handleNum = 0;int handlecut = 0; void HandleIo( SOCKET_OBJ * sock, BUFFER_OBJ_EX * buf, HANDLE CompPort, DWORD BytesTransfered, DWORD error ) {    SOCKET_OBJ * clientobj= NULL ; // New client object for accepted connections    BUFFER_OBJ_EX * recvobj= NULL , // Used to post new receives on accepted connections               * sendobj= NULL ; // Used to post new sends for data received    BOOL bCleanupSocket;    char * tmp;    int i;     bCleanupSocket = FALSE ;     if ( ( error ! = NO_ERROR) & & ( gProtocol = = IPPROTO_TCP ) ) {        FreeBufferObjEx( buf) ;         if ( InterlockedDecrement( & sock- > OutstandingOps) = = 0) {            FreeSocketObj( sock) ;        }        return ;    }     EnterCriticalSection( & sock- > SockCritSec) ;     if ( buf- > operation = = OP_ACCEPT) {        HANDLE hrc;        SOCKADDR_STORAGE * LocalSockaddr= NULL ,                         * RemoteSockaddr= NULL ;        int LocalSockaddrLen,                          RemoteSockaddrLen;         sock- > lpfnGetAcceptExSockaddrs(                buf- > buf, buf- > buflen - ( ( sizeof ( SOCKADDR_STORAGE) + 16) * 2) ,                sizeof ( SOCKADDR_STORAGE) + 16, sizeof ( SOCKADDR_STORAGE) + 16,                ( SOCKADDR * * ) & LocalSockaddr, & LocalSockaddrLen,                ( SOCKADDR * * ) & RemoteSockaddr, & RemoteSockaddrLen) ;         clientobj = GetSocketObj( buf- > sclient, sock- > af) ;         hrc = CreateIoCompletionPort( ( HANDLE) buf- > sclient, CompPort, ( ULONG_PTR) clientobj, 0) ;        if ( hrc = = NULL ) {            fprintf ( stderr , "CompletionThread: CreateIoCompletionPort failed: %d/n" , GetLastError( ) ) ;            return ;        }         sendobj = GetBufferObjEx( BytesTransfered) ;        memcpy ( sendobj- > buf, buf- > buf, BytesTransfered) ;         if ( PostSend( clientobj, sendobj) = = NO_ERROR)        {            // Now post some receives on this new connection            for ( i = 0; i < gOverlappedCount; i+ + )            {                recvobj = GetBufferObjEx( gBufferSize) ;                 if ( PostRecv( clientobj, recvobj) ! = NO_ERROR)                {                    FreeBufferObjEx( recvobj) ;                    error = SOCKET_ERROR;                    break ;                }            }        }        else        {            FreeBufferObjEx( sendobj) ;            error = SOCKET_ERROR;        }         PostAccept( sock, buf) ;         if ( error ! = NO_ERROR)        {            if ( clientobj- > OutstandingOps = = 0)            {                closesocket( clientobj- > s) ;                clientobj- > s = INVALID_SOCKET;                FreeSocketObj( clientobj) ;            }            else            {                clientobj- > bClosing = TRUE ;            }            error = NO_ERROR;        }     } else if ( ( buf- > operation = = OP_READ) & & ( error = = NO_ERROR) ) {        if ( ( BytesTransfered > 0) )        {            printf ( "HandleIo: %d/n" , handleNum+ + ) ;            // Create a buffer to send            sendobj = GetBufferObjEx( gBufferSize) ;            printf ( "handlecut %d./n" , handlecut+ + ) ;             // Swap the buffers (i.e. buffer we just received becomes the send buffer)            tmp = sendobj- > buf;            sendobj- > buflen = BytesTransfered;            sendobj- > buf = buf- > buf;            sendobj- > IoOrder = buf- > IoOrder;             buf- > buf = tmp;            buf- > buflen = gBufferSize;             InsertPendingSend( sock, sendobj) ;             if ( DoSends( sock) ! = NO_ERROR)            {                error = SOCKET_ERROR;                printf ( "SOCKET_ERROR./n" ) ;            }            else            {                // Post another receive                if ( PostRecv( sock, buf) ! = NO_ERROR)                {                    // In the event the recv fails, clean up the connection                    FreeBufferObjEx( buf) ;                    error = SOCKET_ERROR;                    printf ( "SOCKET_ERROR./n" ) ;                }            }        }        else        {            sock- > bClosing = TRUE ;             // Free the receive buffer            FreeBufferObjEx( buf) ;             if ( DoSends( sock) ! = NO_ERROR)            {                error = SOCKET_ERROR;                printf ( "SOCKET_ERROR./n" ) ;            }             // If this was the last outstanding operation on socket, clean it up            if ( ( sock- > OutstandingOps = = 0) & & ( sock- > OutOfOrderSends. count = = 0) )            {                bCleanupSocket = TRUE ;            }        }    } else if ( buf- > operation = = OP_WRITE) {        FreeBufferObjEx( buf) ;         if ( DoSends( sock) ! = NO_ERROR)        {            error = SOCKET_ERROR;        }    }     if ( error ! = NO_ERROR) {        sock- > bClosing = TRUE ;    }     if ( ( InterlockedDecrement( & sock- > OutstandingOps) = = 0) & & ( sock- > bClosing) & & ( sock- > OutOfOrderSends. count = = 0) ) {        bCleanupSocket = TRUE ;    } else {        if ( DoSends( sock) ! = NO_ERROR) {            bCleanupSocket = TRUE ;        }    }     LeaveCriticalSection( & sock- > SockCritSec) ;     if ( bCleanupSocket)    {        closesocket( sock- > s) ;        sock- > s = INVALID_SOCKET;         FreeSocketObj( sock) ;    } } int iocpNum = 0; DWORD WINAPI CompletionThread( LPVOID lpParam) {    SOCKET_OBJ * sockobj= NULL ; // Per socket object for completed I/O    BUFFER_OBJ_EX * bufobj= NULL ; // Per I/O object for completed I/O    OVERLAPPED * lpOverlapped= NULL ; // Pointer to overlapped structure for completed I/O    HANDLE CompletionPort; // Completion port handle    DWORD BytesTransfered, // Number of bytes transfered                    Flags; // Flags for completed I/O    int rc,                    error ;     CompletionPort = ( HANDLE) lpParam;    while ( true ) {        error = NO_ERROR;        rc = GetQueuedCompletionStatus( CompletionPort, & BytesTransfered, ( PULONG_PTR) & sockobj, & lpOverlapped, INFINITE) ;        printf ( "iocp %d./n" , iocpNum+ + ) ;        bufobj = CONTAINING_RECORD( lpOverlapped, BUFFER_OBJ_EX, ol) ;         if ( rc = = FALSE )        {            printf ( "false./n" ) ;            rc = WSAGetOverlappedResult( sockobj- > s, & bufobj- > ol, & BytesTransfered, FALSE , & Flags) ;            if ( rc = = FALSE )            {                error = WSAGetLastError( ) ;                printf ( "WSAGetOverlappedResult failed %d./n" , error ) ;            }        }         HandleIo( sockobj, bufobj, CompletionPort, BytesTransfered, error ) ;    }     ExitProcess( 0) ;    return 0;} int _tmain( int argc, _TCHAR* argv[ ] ){    WSADATA wsd;    SYSTEM_INFO sysinfo;    SOCKET_OBJ * sockobj= NULL ;    SocketObjHeader ListenSockets;    HANDLE CompletionPort,                     CompThreads[ MAX_COMPLETION_THREAD_COUNT] ,                     hrc;    int endpointcount= 0,                     interval,                     rc,                     i;    struct addrinfo * res= NULL ,                    * ptr= NULL ;     if ( WSAStartup( MAKEWORD( 2, 2) , & wsd) ! = 0)    {        fprintf ( stderr , "unable to load Winsock!/n" ) ;        return - 1;    }     CompletionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL , NULL , 0) ;    if ( CompletionPort = = NULL ) {        fprintf ( stderr , "CreateIoCompletionPort failed./n" ) ;        return 0;    }     GetSystemInfo( & sysinfo) ;    if ( sysinfo. dwNumberOfProcessors > MAX_COMPLETION_THREAD_COUNT) {        sysinfo. dwNumberOfProcessors = MAX_COMPLETION_THREAD_COUNT;    }        //for (i = 0; i < sysinfo.dwNumberOfProcessors; ++i) {    for ( i = 0; i < 1; + + i) {        CompThreads[ i] = CreateThread( NULL , 0, CompletionThread, ( LPVOID) CompletionPort, 0, NULL ) ;        if ( CompThreads[ i] = = NULL ) {            fprintf ( stderr , "CreateThread failed./n" ) ;            return - 1;        }    }     res = ResolveAddress( gSrvAddr, gPort, gAddressFamily, gSocketType, gProtocol) ;    if ( res = = NULL )    {        fprintf ( stderr , "ResolveAddress failed to return any addresses!/n" ) ;        return - 1;    }     InitializeSingleHead( & ListenSockets) ;     ptr = res;    while ( ptr) {        sockobj = GetSocketObj( INVALID_SOCKET, ptr- > ai_family) ;         sockobj- > s = socket ( ptr- > ai_family, ptr- > ai_socktype, ptr- > ai_protocol) ;        if ( sockobj- > s = = INVALID_SOCKET)        {            fprintf ( stderr , "socket failed: %d/n" , WSAGetLastError( ) ) ;            return - 1;        }         hrc = CreateIoCompletionPort( ( HANDLE) sockobj- > s, CompletionPort, ( ULONG_PTR) sockobj, 0) ;        if ( hrc = = NULL )        {            fprintf ( stderr , "CreateIoCompletionPort failed: %d/n" , GetLastError( ) ) ;            return - 1;        }         rc = bind ( sockobj- > s, ptr- > ai_addr, ptr- > ai_addrlen) ;        if ( rc = = SOCKET_ERROR) {            fprintf ( stderr , "bind failed: %d/n" , WSAGetLastError( ) ) ;            return - 1;        }         if ( gProtocol = = IPPROTO_TCP ) {            BUFFER_OBJ_EX * acceptobj= NULL ;            GUID guidAcceptEx = WSAID_ACCEPTEX,                            guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;            DWORD bytes;             // Need to load the Winsock extension functions from each provider            // -- e.g. AF_INET and AF_INET6.             rc = WSAIoctl( sockobj- > s, SIO_GET_EXTENSION_FUNCTION_POINTER, & guidAcceptEx, sizeof ( guidAcceptEx) ,                   & sockobj- > lpfnAcceptEx, sizeof ( sockobj- > lpfnAcceptEx) , & bytes, NULL , NULL ) ;            if ( rc = = SOCKET_ERROR)            {                fprintf ( stderr , "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER failed: %d/n" ,                        WSAGetLastError( ) ) ;                return - 1;            }             rc = WSAIoctl( sockobj- > s, SIO_GET_EXTENSION_FUNCTION_POINTER, & guidGetAcceptExSockaddrs, sizeof ( guidGetAcceptExSockaddrs) ,                   & sockobj- > lpfnGetAcceptExSockaddrs, sizeof ( sockobj- > lpfnGetAcceptExSockaddrs) , & bytes, NULL , NULL ) ;            if ( rc = = SOCKET_ERROR)            {                fprintf ( stderr , "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER faled: %d/n" ,                        WSAGetLastError( ) ) ;                return - 1;            }             rc = listen ( sockobj- > s, 100) ;            if ( rc = = SOCKET_ERROR) {                fprintf ( stderr , "listen failed: %d/n" , WSAGetLastError( ) ) ;                return - 1;            }             sockobj- > PendingAccepts = ( BUFFER_OBJ_EX * * ) HeapAlloc( GetProcessHeap( ) , HEAP_ZERO_MEMORY, ( sizeof ( BUFFER_OBJ_EX * ) * gOverlappedCount) ) ;            if ( sockobj- > PendingAccepts = = NULL )            {                fprintf ( stderr , "HeapAlloc failed: %d/n" , GetLastError( ) ) ;                ExitProcess( - 1) ;            }             for ( i= 0; i < gOverlappedCount ; i+ + )            {                sockobj- > PendingAccepts[ i] = acceptobj = GetBufferObjEx( gBufferSize) ;                PostAccept( sockobj, acceptobj) ;            }             EnqueueSingleList( & ListenSockets, & ( sockobj- > next) ) ;        }         ptr = ptr- > ai_next;    }     freeaddrinfo ( res) ;     interval = 0;    while ( true ) {        rc = WSAWaitForMultipleEvents( 1, CompThreads, TRUE , 5000, FALSE ) ;        if ( rc = = WAIT_FAILED) {            fprintf ( stderr , "WSAWaitForMultipleEvents failed: %d/n" , WSAGetLastError( ) ) ;            break ;        } else if ( rc = = WAIT_TIMEOUT) {            interval+ + ;             if ( interval = = 12) {                SocketObj * listenptr= NULL ;                int optval,                             optlen;                 // Walk the list of outstanding accepts                listenptr = ( SocketObj * ) GotoNextSingleList( & ListenSockets, ListenSockets. head) ;                while ( listenptr)                {                    sockobj = ( SOCKET_OBJ * ) container_of( SOCKET_OBJ, next, listenptr) ;                    for ( i= 0; i < gOverlappedCount ; i+ + )                    {                        optlen = sizeof ( optval) ;                        rc = getsockopt (                                sockobj- > PendingAccepts[ i] - > sclient,                                SOL_SOCKET,                                SO_CONNECT_TIME,                                ( char * ) & optval,                             & optlen                             ) ;                        if ( rc = = SOCKET_ERROR)                        {                            fprintf ( stderr , "getsockopt: SO_CONNECT_TIME failed: %d/n" , WSAGetLastError( ) ) ;                            return - 1;                        }                        if ( ( optval ! = 0xFFFFFFFF) & & ( optval > 300) )                        {                            closesocket( sockobj- > PendingAccepts[ i] - > sclient) ;                        }                    }                    listenptr = ( SocketObj * ) GotoNextSingleList( & ListenSockets, listenptr) ;                }                interval = 0;            }        }    }     WSACleanup( ) ;     return 0;}

     

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

    最新回复(0)