📄 _socket.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 + -