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 );