# include < winsock2. h> # include < ws2tcpip
. h
> # include "public.h"# include "resolve.h" typedef SINGLE_LIST_HEADER BuffHeader
;typedef SINGLE_LIST BuffObj
;typedef SINGLE_LIST_HEADER TheadObjHeader
;typedef SINGLE_LIST ThreadObj
;typedef DOUBLE_LIST_HEADER SockObjHeader
;typedef DOUBLE_LIST SockObj
; typedef struct _SOCKET_OBJ
{ SOCKET s
; // Socket handle HANDLE event
; // Event 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
; typedef struct _THREAD_OBJ
{ SockObjHeader sockHeader
; HANDLE Event
; // Used to signal new clients assigned // to this thread HANDLE Thread
; HANDLE Handles
[ MAXIMUM_WAIT_OBJECTS
] ; // Array of socket's event handles CRITICAL_SECTION ThreadCritSec
; // Protect access to SOCKET_OBJ lists ThreadObj entry
; // Next thread object in list} THREAD_OBJ
; TheadObjHeader theadObjHeader
; 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
) ; sockobj
- > event
= WSACreateEvent
( ) ; if ( sockobj
- > event
= = NULL ) { fprintf ( stderr , "GetSocketObj: WSACreateEvent failed: %d/n" , WSAGetLastError
( ) ) ; ExitProcess
( - 1
) ; } InitializeCriticalSection
( & sockobj
- > buff
. SendRecvQueueCritSec
) ; return sockobj
;} THREAD_OBJ
* GetThreadObj
( ) { THREAD_OBJ
* thread
= NULL ; thread
= ( THREAD_OBJ
* ) HeapAlloc
( GetProcessHeap
( ) , HEAP_ZERO_MEMORY
, sizeof ( THREAD_OBJ
) ) ; if ( thread
= = NULL ) { fprintf ( stderr , "HeapAllco failed./n" ) ; ExitProcess
( - 1
) ; } thread
- > Event
= WSACreateEvent
( ) ; if ( thread
- > Event
= = NULL ) { fprintf ( stderr , "WSACreateEvent failed./n" ) ; ExitProcess
( - 1
) ; } thread
- > Handles
[ 0
] = thread
- > Event
; InitializeCriticalSection
( & thread
- > ThreadCritSec
) ; InitializeDoubleHead
( & thread
- > sockHeader
) ; return thread
;} int InsertSocketObj
( THREAD_OBJ
* thread
, SOCKET_OBJ
* sockobj
) { int ret
; EnterCriticalSection
( & thread
- > ThreadCritSec
) ; if ( thread
- > sockHeader
. count < MAXIMUM_WAIT_OBJECTS
- 1
) { EnqueueDoubleListHead
( & ( thread
- > sockHeader
) , & ( sockobj
- > entry
) ) ; thread
- > Handles
[ thread
- > sockHeader
. count ] = sockobj
- > event
; ret
= NO_ERROR
; } else { ret
= SOCKET_ERROR
; } LeaveCriticalSection
( & thread
- > ThreadCritSec
) ; return ret
;} SOCKET_OBJ
* FindSocketObj
( THREAD_OBJ
* thread
, int index
) { SOCKET_OBJ
* sockobj
= NULL ; int i
; EnterCriticalSection
( & thread
- > ThreadCritSec
) ; SockObj
* sptr
= ( SockObj
* ) GotoNextDoubleList
( & thread
- > sockHeader
, & ( thread
- > sockHeader
. head
) ) ; for ( i
= 0
; i
< index
; + + i
) { if ( sptr
= = NULL ) { fprintf ( stderr , "FindSocketobj failed./n" ) ; ExitProcess
( - 1
) ; } sptr
= ( SockObj
* ) GotoNextDoubleList
( & thread
- > sockHeader
, sptr
) ; } sockobj
= ( SOCKET_OBJ
* ) container_of
( SOCKET_OBJ
, entry
, sptr
) ; LeaveCriticalSection
( & thread
- > ThreadCritSec
) ; return sockobj
;} void RemoveSocketObj
( THREAD_OBJ
* thread
, SOCKET_OBJ
* sock
) { EnterCriticalSection
( & thread
- > ThreadCritSec
) ; RemoveDoubleList
( & thread
- > sockHeader
, & sock
- > entry
) ; WSASetEvent
( thread
- > Event
) ; LeaveCriticalSection
( & thread
- > ThreadCritSec
) ;} 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
) ; } WSACloseEvent
( obj
- > event
) ; if ( obj
- > s
! = INVALID_SOCKET
) { closesocket
( obj
- > s
) ; } HeapFree
( GetProcessHeap
( ) , 0
, obj
) ;} void RenumberThreadArray
( THREAD_OBJ
* thread
) { EnterCriticalSection
( & thread
- > ThreadCritSec
) ; SOCKET_OBJ
* obj
= NULL ; int i
= 0
; SockObj
* sptr
= NULL ; sptr
= ( SockObj
* ) GotoNextDoubleList
( & thread
- > sockHeader
, & ( thread
- > sockHeader
. head
) ) ; while ( sptr
) { obj
= ( SOCKET_OBJ
* ) container_of
( SOCKET_OBJ
, entry
, sptr
) ; thread
- > Handles
[ + + i
] = obj
- > event
; sptr
= ( SockObj
* ) GotoNextDoubleList
( & thread
- > sockHeader
, sptr
) ; } LeaveCriticalSection
( & thread
- > ThreadCritSec
) ;} int ReceivePendingData
( SOCKET_OBJ
* sockobj
) { BUFFER_OBJ
* buffobj
= NULL ; int rc
, ret
; // Get a buffer to receive the data buffobj
= GetBufferObj
( gBufferSize
) ; ret
= 0
; if ( gProtocol
= = IPPROTO_TCP ) { rc
= recv ( sockobj
- > s
, buffobj
- > buf
, buffobj
- > buflen
, 0
) ; } else { fprintf ( stderr , "Tcp failed./n" ) ; ExitProcess
( - 1
) ; } if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "recv failed./n" ) ; ExitProcess
( - 1
) ; } else if ( rc
= = 0
) { FreeBufferObj
( buffobj
) ; sockobj
- > closing
= TRUE ; if ( sockobj
- > buff
. head
= = NULL ) { // If no sends are pending, close the socket for good closesocket
( sockobj
- > s
) ; sockobj
- > s
= INVALID_SOCKET
; ret
= - 1
; } else { ret
= 0
; } } else { buffobj
- > buflen
= rc
; EnqueueSingleList
( & sockobj
- > buff
, & buffobj
- > next
) ; ret
= 1
; } 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
; } } printf ( "send %d./n" , bufobj
- > buflen
) ; FreeBufferObj
( bufobj
) ; } else { ExitProcess
( - 1
) ; } } if ( ( sock
- > buff
. head
= = NULL ) & & ( sock
- > closing
= = TRUE ) ) { closesocket
( sock
- > s
) ; sock
- > s
= INVALID_SOCKET
; ret
= - 1
; printf ( "Closing Connection./n" ) ; } return ret
;} int HandleIo
( THREAD_OBJ
* thread
, SOCKET_OBJ
* sock
) { WSANETWORKEVENTS nevents
; int rc
; // Enumerate the events rc
= WSAEnumNetworkEvents
( sock
- > s
, sock
- > event
, & nevents
) ; if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "HandleIo: WSAEnumNetworkEvents failed: %d/n" , WSAGetLastError
( ) ) ; return SOCKET_ERROR
; } if ( nevents
. lNetworkEvents
& FD_READ
) { if ( nevents
. iErrorCode
[ FD_READ_BIT
] = = 0
) { rc
= ReceivePendingData
( sock
) ; if ( rc
= = - 1
) { RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } rc
= SendPendingData
( sock
) ; if ( rc
= = - 1
) { RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } } else { fprintf ( stderr , "HandleIo: FD_READ error %d/n" , nevents
. iErrorCode
[ FD_READ_BIT
] ) ; RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } } if ( nevents
. lNetworkEvents
& FD_WRITE
) { if ( nevents
. iErrorCode
[ FD_WRITE_BIT
] = = 0
) { rc
= SendPendingData
( sock
) ; if ( rc
= = - 1
) { RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } } else { fprintf ( stderr , "HandleIo: FD_WRITE error %d/n" , nevents
. iErrorCode
[ FD_WRITE_BIT
] ) ; return SOCKET_ERROR
; } } if ( nevents
. lNetworkEvents
& FD_CLOSE
) { if ( nevents
. iErrorCode
[ FD_CLOSE_BIT
] = = 0
) { // Socket has been indicated as closing so make sure all the data // has been read printf ( "close./n" ) ; while ( 1
) { rc
= ReceivePendingData
( sock
) ; if ( rc
= = - 1
) { RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } else if ( rc
! = 0
) { continue ; } else { break ; } } // See if there is any data pending, if so try to send it rc
= SendPendingData
( sock
) ; if ( rc
= = - 1
) { RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } } else { fprintf ( stderr , "HandleIo: FD_CLOSE error %d/n" , nevents
. iErrorCode
[ FD_CLOSE_BIT
] ) ; RemoveSocketObj
( thread
, sock
) ; FreeSocketObj
( sock
) ; return SOCKET_ERROR
; } } return NO_ERROR
;} DWORD WINAPI ChildThread
( LPVOID lpParam
) { THREAD_OBJ
* thread
= NULL ; SOCKET_OBJ
* sptr
= NULL , * sockobj
= NULL ; int index
, rc
, i
; thread
= ( THREAD_OBJ
* ) lpParam
; while ( true ) { rc
= WaitForMultipleObjects
( thread
- > sockHeader
. count + 1
, thread
- > Handles
, FALSE , INFINITE
) ; if ( rc
= = WAIT_FAILED
| | rc
= = WAIT_TIMEOUT
) { fprintf ( stderr , "ChildThread: WaitForMultipleObjects failed: %d/n" , GetLastError
( ) ) ; break ; } else { for ( i
= 0
; i
< thread
- > sockHeader
. count + 1
; i
+ + ) { rc
= WaitForSingleObject
( thread
- > Handles
[ i
] , 0
) ; if ( rc
= = WAIT_FAILED
) { fprintf ( stderr , "ChildThread: WaitForSingleObject failed: %d/n" , GetLastError
( ) ) ; ExitThread
( - 1
) ; } else if ( rc
= = WAIT_TIMEOUT
) { // This event isn't signaled, continue to the next one continue ; } index
= i
; if ( index
= = 0
) { // If index 0 is signaled then rebuild the array of event // handles to wait on WSAResetEvent
( thread
- > Handles
[ index
] ) ; RenumberThreadArray
( thread
) ; i
= 1
; } else { sockobj
= FindSocketObj
( thread
, index
- 1
) ; if ( sockobj
! = NULL ) { if ( HandleIo
( thread
, sockobj
) = = SOCKET_ERROR
) { RenumberThreadArray
( thread
) ; } } else { printf ( "Unable to find socket object!/n" ) ; } } } } }} void AssignToFreeThread
( SOCKET_OBJ
* sock
) { ThreadObj
* threadobj
= NULL ; THREAD_OBJ
* thread
= NULL ; threadobj
= ( ThreadObj
* ) GotoNextSingleList
( & theadObjHeader
, theadObjHeader
. head
) ; while ( threadobj
) { thread
= ( THREAD_OBJ
* ) container_of
( THREAD_OBJ
, entry
, threadobj
) ; if ( InsertSocketObj
( thread
, sock
) ! = SOCKET_ERROR
) { break ; } threadobj
= ( ThreadObj
* ) GotoNextSingleList
( & theadObjHeader
, threadobj
) ; } if ( threadobj
= = NULL ) { thread
= GetThreadObj
( ) ; thread
- > Thread
= CreateThread
( NULL , 0
, ChildThread
, ( LPVOID
) thread
, 0
, NULL ) ; if ( thread
- > Thread
= = NULL ) { fprintf ( stderr , "AssignToFreeThread: CreateThread failed: %d/n" , GetLastError
( ) ) ; ExitProcess
( - 1
) ; } InsertSocketObj
( thread
, sock
) ; EnqueueSingleList
( & theadObjHeader
, & thread
- > entry
) ; } WSASetEvent
( thread
- > Event
) ;} int _tmain
( int argc
, _TCHAR
* argv
[ ] ){ WSADATA wsd
; struct addrinfo * res
= NULL , * ptr
= NULL ; THREAD_OBJ
* thread
= NULL ; SOCKET_OBJ
* sockobj
= NULL , * newsock
= NULL ; int index
, rc
; if ( WSAStartup
( MAKEWORD
( 2
, 2
) , & wsd
) ! = 0
) { fprintf ( stderr , "unable to load Winsock!/n" ) ; return - 1
; } res
= ResolveAddress
( gSrvAddr
, gPort
, gAddressFamily
, gSocketType
, gProtocol
) ; if ( res
= = NULL ) { fprintf ( stderr , "ResolveAddress failed to return any addresses!/n" ) ; return - 1
; } thread
= GetThreadObj
( ) ; InitializeCriticalSection
( & theadObjHeader
. SendRecvQueueCritSec
) ; theadObjHeader
. head
= theadObjHeader
. tail
= NULL ; ptr
= res
; while ( ptr
) { sockobj
= GetSocketObj
( INVALID_SOCKET
, ( gProtocol
= = IPPROTO_TCP ) ? TRUE : FALSE ) ; sockobj
- > s
= socket ( ptr
- > ai_family
, ptr
- > ai_socktype
, ptr
- > ai_protocol
) ; if ( sockobj
- > s
= = INVALID_SOCKET
) { fprintf ( stderr , "create socket failed./n" ) ; ExitProcess
( - 1
) ; } InsertSocketObj
( thread
, sockobj
) ; 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 ) { rc
= listen ( sockobj
- > s
, 200
) ; if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "listen failed./n" ) ; ExitProcess
( - 1
) ; } rc
= WSAEventSelect
( sockobj
- > s
, sockobj
- > event
, FD_ACCEPT
| FD_CLOSE
) ; if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "WSAEventSelect failed: %d/n" , WSAGetLastError
( ) ) ; ExitProcess
( - 1
) ; } } ptr
= ptr
- > ai_next
; } freeaddrinfo ( res
) ; while ( true ) { rc
= WaitForMultipleObjects
( thread
- > sockHeader
. count + 1
, thread
- > Handles
, FALSE , 5000
) ; if ( rc
= = WAIT_FAILED
) { fprintf ( stderr , "WaitForMultipleObjects failed:%d/n" , WSAGetLastError
( ) ) ; break ; } else if ( rc
= = WAIT_TIMEOUT
) { continue ; } else { index
= rc
- WAIT_OBJECT_0
; sockobj
= FindSocketObj
( thread
, index
- 1
) ; if ( gProtocol
= = IPPROTO_TCP ) { SOCKADDR_STORAGE sa
; WSANETWORKEVENTS ne
; SOCKET sc
; int salen
; rc
= WSAEnumNetworkEvents
( sockobj
- > s
, thread
- > Handles
[ index
] , & ne
) ; if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "WSAEnumNetworkEvents failed./n" ) ; break ; } while ( true ) { sc
= INVALID_SOCKET
; salen
= sizeof ( sa
) ; sc
= accept ( sockobj
- > s
, ( SOCKADDR * ) & sa
, & salen
) ; if ( ( sc
= = INVALID_SOCKET
) & & ( WSAGetLastError
( ) ! = WSAEWOULDBLOCK
) ) { fprintf ( stderr , "accept failed./n" ) ; break ; } else if ( sc
= = INVALID_SOCKET
) { continue ; } else { newsock
= GetSocketObj
( INVALID_SOCKET
, FALSE ) ; memcpy ( & newsock
- > addr
, & sa
, salen
) ; newsock
- > addrlen
= salen
; newsock
- > s
= sc
; rc
= WSAEventSelect
( newsock
- > s
, newsock
- > event
, FD_READ
| FD_WRITE
| FD_CLOSE
) ; if ( rc
= = SOCKET_ERROR
) { fprintf ( stderr , "WSAEventSelect failed: %d/n" , WSAGetLastError
( ) ) ; break ; } AssignToFreeThread
( newsock
) ; } } } } } WSACleanup
( ) ; return 0
;}
版权声明: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。