www.pudn.com > IOCP完成端口模型示例代码 .zip > worker.h
// options to play with // if defined, cose will use WsaSend(), else WriteFile() #define USE_WSASEND 1 // if defined, code will use WSARecv(), else ReadFile() #define USE_WSARECV 1 // if defined, the server will not wait for the client to start // talking; instead, it will send a banner line and _then_ begin // receiving. Obviously enough, with the initial buffer size in // the AcceptEx() call set to 0, GetAcceptExSockaddrs() must // fail; what is curious is that _any_ later attempt to retrieve // the socket's peer name also fail. Bleurgh! #define SEND_BANNER_FIRST 1 #define BANNER_STRING "Welcome to the sockhim server. \"help\" for help.\r\n" extern long runningThreads; extern HANDLE hiocp; extern HANDLE suicideEvent; extern int concurrency; #define VALID(h) ( (h) != 0 && (h) != INVALID_HANDLE_VALUE ) // IOCP worker function declaration unsigned int __stdcall Worker( void *arg ); // OVERLAPPED wrapper to use as connection context // I don't use completion keys; instead, I use the // OVERLAPPED pointer to get at my OV struct below. // this frees up the completion key, which I only // use to tell my workers to commit suicide. #define COMPKEY_DIEDIEDIE ((DWORD) -1L) enum State { stClosed, stAccepting, stReading, stWriting, stSendingFile }; // inheriting from OVERLAPPED limits us to // one outstanding I/O per connection. Ask // me if I care ... struct OV: public OVERLAPPED { static const int addrlen; static const int initialReceiveSize; const enum { bs = 4096 }; DWORD tag; int ix; // makes debugging easier State state; // what the connection is doing SOCKET s; // the connection's socket handle DWORD n; // number of bytes received or sent char *end; // points to first free byte in buf bool ignore; // == true to ignore rest of currently received line string reply; // the reply will be built in this buffer sockaddr_in local, peer; // addresses // the following stuff keeps temporary state for transmitting a file bool sendFile; // true if we have a file to send HANDLE hf; // file handle string tfHead, tfTail; // header and trailer for the file TRANSMIT_FILE_BUFFERS tfb; // to pass the head/tail to TF() char buf[bs]; // receive buffer #ifdef USE_WSASEND // no array, as we won't ever transmit more than one buffer at a time WSABUF sendBufferDescriptor; #endif #ifdef USE_WSARECV // no array, as we won't ever transmit more than one buffer at a time WSABUF recvBufferDescriptor; DWORD recvFlags; // needed by WSARecv() #endif OV(): tag( '@@@@' ), state( stClosed ), ignore( false ), sendFile( false ), s( SOCKET_ERROR ), end( &buf[0] ) { Internal = InternalHigh = Offset = OffsetHigh = 0; hEvent = 0; } OV( const OV &o ) { tag = o.tag; ix = o.ix; state = o.state; s = o.s; n = o.n; end = &buf[0] + ( o.end - &o.buf[0] ); ignore = o.ignore; reply = o.reply; local = o.local; peer = o.peer; sendFile = false; hf = INVALID_HANDLE_VALUE; memcpy( buf, o.buf, bs ); } ~OV() { tag = '----'; } // real cleanup handled by main function }; typedef list< OV * > OL; typedef OL::iterator OLI; // scavenger function declaration struct ScavengerArgs { OL *povl; int delay; // milliseconds between two runs of the idle socket scavenger int timeout; // max idle time before first data on a socket, in milliseconds HANDLE suicideEvent; // tells scavenger when to die }; unsigned int __stdcall ScavengePulingSockets( void *arg ); // see definitions in worker.cpp void DoIo( OV &ov ); void DoClose( OV &ov, bool force = false, bool listenAgain = true ); void ReinitContext( OV &ov ); void PostRead( OV &ov ); void SendReply( OV &ov ); bool DoCommands( OV &ov ); void DoOneCommand( char *p, OV &ov );