⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _socket.h

📁 http代理程序
💻 H
字号:
#ifndef ___sockets_h__
#define ___sockets_h__


#include <windows.h>

#include <streambuf>
#include <iostream>
using namespace std;

#include "_exception.h"


namespace extension
{

/*
Exception raised when an error occures on a socket
*/
class socket_exception :
	public extended_exception
{
public:

	socket_exception( long nCode, const char* pDescription = "Socket exception", const char* pFile = "", long nLine = -1 ) :
	  extended_exception( nCode, pDescription, pFile, nLine )
	{
	}
};



/*
Automatic socklib initialization
*/
class use_sockets
{
public:


	// Function name	: use_sockets
	// Description	    : 
	// Return type		: 
	// Argument         :  WORD wVersionRequested
	// Argument         : WSADATA* pWSAData = NULL
	use_sockets( WORD wVersionRequested, WSADATA* pWSAData = NULL )
		throw( socket_exception )
	{
		m_bInitialized = false;

		WSADATA wsaData;
		if( ::WSAStartup( wVersionRequested, &wsaData ) != 0 )
			throw_exception( socket_exception, ::WSAGetLastError(), "Unable to initialize socket library" );

		if( LOBYTE( wsaData.wHighVersion ) < LOBYTE( wVersionRequested ) ||
			LOBYTE( wsaData.wHighVersion ) == LOBYTE( wVersionRequested ) && HIBYTE( wsaData.wHighVersion ) < HIBYTE( wVersionRequested ) )
			throw_exception( socket_exception, extended_exception::exception_code_generic, "Winsock requested version is bigger than available version" );

		m_bInitialized = true;
	}



	// Function name	: ~use_sockets
	// Description	    : 
	// Return type		: virtual 
	virtual ~use_sockets()
	{
		if( m_bInitialized )
			::WSACleanup();
	}

private:

	// Disable copy
	use_sockets( const use_sockets& );
	// Disable asignment
	use_sockets& operator=( const use_sockets& );
	
	// true if Winsock was succesfully initialized and false otherwise
	bool m_bInitialized;
};

/*
Base class for sockets
*/
class socket
{
public:
	
	// Function name	: set_blocking_mode
	// Description	    : Constrols the blocking mode of the buffer
	// Return type		: bool 
	// Argument         : bool b
	bool set_blocking_mode( bool b )
	{
		unsigned long uArg = !b;
		return ( ioctlsocket( m_hSocket, FIONBIO, &uArg ) == 0 );
	}

	// Function name	: is_open
	// Description	    : Check if the socket is open or closed
	// Return type		: bool 
    bool is_open() const
	{
		return INVALID_SOCKET != m_hSocket;
	}


protected:

	// Win32 socket handle
	SOCKET m_hSocket;


	// Function name	: socket
	// Description	    : Default constructor
	// Return type		: 
	socket()
	{
		m_hSocket = INVALID_SOCKET;
	}


	// Function name	: str_to_inet_addr
	// Description	    : Convert the given string 
	// Return type		: long 
	// Argument         : const char* strAddr
	static long str_to_inet_addr( const char* strAddr )
	{
		long lInetAddr = INADDR_NONE;

		// Try to convert the ip address
		lInetAddr = ::inet_addr( strAddr );
		if( lInetAddr == INADDR_NONE )
		{
			// Get the host's ip address
			struct hostent* pHostEnt = ::gethostbyname( strAddr );
			if( pHostEnt == NULL )
				return NULL;

			// Try to convert the ip address
			lInetAddr = *reinterpret_cast< long* >( pHostEnt->h_addr_list[0] );
			if( lInetAddr == INADDR_NONE )
				return NULL;
		}

		return lInetAddr;
	}

};


/*
Socket buffer
*/
template < class E, class T = char_traits< E > >
class basic_sockbuf : 
	public socket,
	public basic_streambuf< E, T > 
{
public:
    

	// Function name	: basic_sockbuf
	// Description	    : Constructs an socket buffer based on the argument socket
	// Return type		: 
	basic_sockbuf( SOCKET hSocket = INVALID_SOCKET )
	{
		m_hSocket = hSocket;
	}


	// Function name	: ~basic_sockbuf
	// Description	    : Closes the socket if is open
	// Return type		: virtual 
	virtual ~basic_sockbuf()
	{
		if( is_open() )
			close();
	}

	// Function name	: *open
	// Description	    : Opens the socket
	// Return type		: basic_sockbuf 
	// Argument         : const char *s
	// Argument         : ios_base::openmode mode
    basic_sockbuf *open(const char *strAddr, short sPort, ios_base::openmode mode)
	{
		long lInetAddr = str_to_inet_addr( strAddr );
		if( lInetAddr == INADDR_NONE )
			return NULL;
	
		// Here we have the ip address of the host on which we want to connect

		m_hSocket = ::socket( AF_INET, SOCK_STREAM, 0 );
		if( m_hSocket == INVALID_SOCKET )
			return NULL;

		// Construct the scokaddr structure
		sockaddr_in saRemote;
		::memset( &saRemote, 0, sizeof( saRemote ) );
		saRemote.sin_family  = AF_INET;
		saRemote.sin_port = htons( sPort );
		saRemote.sin_addr.S_un.S_addr = lInetAddr;

		// Try to connect to remote host
		if( ::connect( m_hSocket, reinterpret_cast< struct sockaddr* >( &saRemote ), sizeof( saRemote ) ) != 0 )
			return NULL;
	
		// Here the socket is connected

		// Enable keep alives
		BOOL bKeepAlive = TRUE;
		::setsockopt( m_hSocket, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast< char* >( &bKeepAlive ), sizeof( bKeepAlive ) );

		// Enable linger
		linger l = { 1, 1 };
		::setsockopt( m_hSocket, SOL_SOCKET, SO_LINGER, reinterpret_cast< char* >( &l ), sizeof( l ) );

		return this;
	}

	// Function name	: *close
	// Description	    : Close the socket
	// Return type		: basic_sockbuf 
    basic_sockbuf *close()
	{
		if( m_hSocket == INVALID_SOCKET )
			return NULL;

		set_blocking_mode( true );
		::closesocket( m_hSocket );
		m_hSocket = INVALID_SOCKET;

		return this;
	}


protected:
    

	// Function name	: underflow
	// Description	    : Reads the first character from the buffer but it does not remove it
	// Return type		: virtual int_type 
	virtual int_type underflow()
	{
		E ch;
		if( ::recv( m_hSocket, reinterpret_cast< char* >( &ch ), sizeof( ch ), MSG_PEEK ) != sizeof( ch ) )
			return T::eof();

		return T::to_int_type( ch );
	}


	// Function name	: uflow
	// Description	    : Reads and removes a character from the socket
	// Return type		: virtual int_type 
	virtual int_type uflow()
	{
		E ch;
		if( ::recv( m_hSocket, reinterpret_cast< char* >( &ch ), sizeof( ch ), 0 ) != sizeof( ch ) )
			return T::eof();

		return T::to_int_type( ch );
	}

	

	// Function name	: xsgetn
	// Description	    : Extracts up to n elements from the input stream
	// Return type		: streamsize		- The number of elements actually extracted.
	// Argument         : E *s				- Buffer
	// Argument         : streamsize n		- Buffer size
	virtual streamsize xsgetn(E *s, streamsize n)
	{
		if( n <= 0 )
			return 0;

		int nReceived = ::recv( m_hSocket, reinterpret_cast< char* >( s ), n * sizeof( E ), 0 );
		if( nReceived == SOCKET_ERROR )
			if( ::WSAGetLastError() != WSAEWOULDBLOCK )
			{
				close();
				return -1;
			}
			else
				return 0;
		else
			if( nReceived == 0 )
				return -1;			
			
		return nReceived;
	}

	// Function name	: overflow
	// Description	    : Writes a character to through the socket
	// Return type		: int_type 
	// Argument         : int_type c = T::eof()
    virtual int_type overflow(int_type c = T::eof())
	{
		if( T::eq_int_type( T::eof(), c ) )
			return T::not_eof( c );

		E ch = T::to_char_type( c );
		if( ::send( m_hSocket, reinterpret_cast< char* >( &ch ), sizeof( ch ), 0 ) != sizeof( ch ) )
			return T::eof();

		return T::not_eof( ch );
	}	

	// Function name	: xsputn
	// Description	    : Inserts up to n elements into the output stream
	// Return type		: streamsize		- The number of elements actually inserted
	// Argument         : const E *s		- Buffer
	// Argument         : streamsize n		- Buffer size
	virtual streamsize xsputn(const E *s, streamsize n)
	{
		if( n <= 0 )
			return 0;

		int nSent = ::send( m_hSocket, const_cast< char* >( s ), n * sizeof( E ), 0 );
		if( nSent == SOCKET_ERROR )
			if( ::WSAGetLastError() != WSAEWOULDBLOCK )
			{
				close();
				return -1;
			}
			else
				return 0;

		return nSent;
	}


	// Function name	: showmanyc
	// Description	    : Returns how many characters are available
	// Return type		: virtual int 
	virtual int showmanyc()
	{
		unsigned long uAvailable = 0;
		if( ::ioctlsocket( m_hSocket, FIONREAD, &uAvailable ) != 0 )
		{
			close();
			return 0;
		}

		return uAvailable;
	}
	
};

/*
Server socket
*/
template < class E, class T = char_traits< E > >
class server_socket :
	public socket
{
public:


	// Function name	: server_socket
	// Description	    : Default constructor for server socket
	// Return type		: 
	server_socket()		
	{
	}


	// Function name	: server_socket
	// Description	    : 
	// Return type		: 
	// Argument         : short sPort
	server_socket( short sPort )
		throw( socket_exception )
	{
		open( sPort );
	}


	// Function name	: ~server_socket
	// Description	    : 
	// Return type		: virtual 
	virtual ~server_socket()
	{
		if( is_open() )
			close();
	}


	// Function name	: open
	// Description	    : Opens a listening socket on the specified port
	// Return type		: void 
	// Argument         : short sPort
	void open( short sPort )
		throw( socket_exception )
	{
		// Create the win32 socket object
		m_hSocket = ::socket( AF_INET, SOCK_STREAM, 0 );
		if( m_hSocket == INVALID_SOCKET )
			throw_exception( socket_exception, ::WSAGetLastError(), "Failed to create the socket" );
		
		// Construct the sockaddr structure
		sockaddr_in saLocal;
		::memset( &saLocal, 0, sizeof( saLocal ) );
		saLocal.sin_family  = AF_INET;
		saLocal.sin_port = htons( sPort );
		saLocal.sin_addr.S_un.S_addr = INADDR_ANY;

		// Bind the socket to local port
		if( ::bind( m_hSocket, reinterpret_cast< sockaddr* >( &saLocal ), sizeof( saLocal ) ) != 0 )
			throw_exception( socket_exception, ::WSAGetLastError(), "Failed to bind the socket" );

		// Listen
		if( ::listen( m_hSocket, 5 ) != 0 )
			throw_exception( socket_exception, ::WSAGetLastError(), "Failed to initiate listening on the socket" );
	}	



	// Function name	: accept
	// Description	    : Accepts a connection on this socket
	// Return type		: basic_sockbuf< E, T >*	
	basic_sockbuf< E, T >* accept()
		throw( socket_exception )
	{
		SOCKET hSocket = ::accept( m_hSocket, NULL,  NULL );
		if( hSocket == INVALID_SOCKET )
			throw_exception( socket_exception, ::WSAGetLastError(), "Failed to accept a connection" );
		return new basic_sockbuf< E, T >( hSocket );
	}

	// Function name	: close
	// Description	    : Close the socket
	// Return type		: void 
	void close()
		throw( socket_exception )
	{
		if( m_hSocket != INVALID_SOCKET )
		{
			::closesocket( m_hSocket );
			m_hSocket = INVALID_SOCKET;
		}

	}

};


/*
Basic socket stream
*/
template <class E, class T = char_traits<E> >
class basic_sockstream : public basic_iostream<E, T> {

public:


	// Function name	: basic_sockstream
	// Description	    : 
	// Return type		: explicit 
	// Argument         : SOCKET hSocket = INVALID_SOCKET
    explicit basic_sockstream( SOCKET hSocket = INVALID_SOCKET ) : 
		basic_iostream< E, T >( ( m_psbBuffer = new basic_sockbuf< E, T >( hSocket ) ) )
	{		
	}


	// Function name	: basic_sockstream
	// Description	    : Constructs s sockstream using the specified socket buffer
	// Return type		: explicit 
	// Argument         : basic_sockbuf< E, T >* psbBuffer
	explicit basic_sockstream( basic_sockbuf< E, T >* psbBuffer ) :
		basic_iostream< E, T >( ( m_psbBuffer = psbBuffer ) )
	{
	}


	// Function name	: basic_sockstream
	// Description	    : 
	// Return type		:
	// Argument         : const char *strAddr
	// Argument         : int iPort
	// Argument         : ios_base::openmode mode = ios_base::in | ios_base::out | ios_base::binary
	explicit basic_sockstream( const char *strAddr, int iPort, ios_base::openmode mode = ios_base::in | ios_base::out | ios_base::binary ) :
		basic_iostream< E, T >( ( m_psbBuffer = new basic_sockbuf< E, T >() ) )
	{
		m_psbBuffer->open( strAddr, iPort, mode );
	}


	// Function name	: ~basic_sockstream
	// Description	    : Destroys the object
	// Return type		: virtual 
	virtual ~basic_sockstream()
	{
		if( is_open() )
			close();
		delete m_psbBuffer;
	}    

	// Function name	: is_open
	// Description	    : 
	// Return type		: bool 
    bool is_open() const
	{
		return m_psbBuffer->is_open();
	}


	// Function name	: open
	// Description	    : 
	// Return type		: void 
	// Argument         : const char *strAddr
	// Argument         : int iPort
	// Argument         : ios_base::openmode mode = ios_base::in | ios_base::out | ios_base::binary
    void open(const char *strAddr, int iPort, ios_base::openmode mode = ios_base::in | ios_base::out | ios_base::binary )
	{
		if( m_psbBuffer->open( strAddr, iPort, mode ) == NULL )
			setstate( failbit );
	}


	// Function name	: close
	// Description	    : 
	// Return type		: void 
    void close()
	{
		if( m_psbBuffer->close() == NULL )
			setstate( failbit );
	}


	// Function name	: set_blocking_mode
	// Description	    : Constrols the blocking mode of the stream
	// Return type		: bool 
	// Argument         : bool b
	bool set_blocking_mode( bool b )
	{
		return m_psbBuffer->set_blocking_mode( b );	
	}

private:

	// Socket buffer
	basic_sockbuf< E, T >* m_psbBuffer;
};

typedef basic_sockstream< char > sockstream;
typedef basic_sockstream< wchar_t > wsockstream;

}
//
#endif // ___sockets_h__

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -