📄 socket.h
字号:
/************************************************************************************
* *
* Title: socket.h *
* *
* Permission to use, copy, modify and distribute this software and it's docu- *
* mentation for any purpose and without fee is hereby granted, provided that *
* this notice remain part of the source files. This package is provided as is, *
* without any support. *
* *
* Corrections and enhancements are welcome. *
* Author's address: meessen@cppm.in2p3.fr *
* *
* *
*************************************************************************************
* *
* Autors: Christophe MEESSEN *
* *
* Date: apr 1999 *
* *
*************************************************************************************/
// Note: an STL ios_baseTREAM compatible source of socket.h and an STL sockstream
// are also available.
#ifndef _BASIC_SOCKET_
#define _BASIC_SOCKET_
#if _MSC_VER > 1000
#pragma once
#endif
#include <new>
// OS Specific includes
#ifdef WIN32
#include <iostream>
#include <windows.h>
#include <sys/types.h>
#else
#define BSD_COMP
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
extern "C"{
int gethostname(char*,int);
}
#define SOCKET int
#define INADDR_NONE -1
#define SOCKET_ERROR -1
#define ioctlsocket ioctl
#define closesocket close
#define _STD_BEGIN
#define _STD_END
#ifdef _Linux__
#define MSG_MAXIOVLEN 16
#define SOMAXCONN 5
#endif // _Linux__
#endif
#ifdef _MSC_VER
#pragma pack(push,8)
#endif /* _MSC_VER */
// socket address classes (may be needed for unix)
//struct sockaddr;
#ifdef WIN32
_STD_BEGIN
#endif
extern "C" {
inline int sockInit()
{
#ifdef WIN32
WSADATA d;
return ::WSAStartup( MAKEWORD( 2, 0 ), &d );
#else
return 0;
#endif
}
}
// ABSTRACT SOCKADDR BASE CLASS
class sockAddr {
public:
virtual ~sockAddr() {}
virtual operator void* () const =0;
operator sockaddr* () const { return addr(); }
virtual int size () const =0;
virtual int family () const =0;
virtual sockaddr* addr () const =0;
};
//////////////////////////////////////////////////////////
// INTERNET SOCKET ADDRESS
// Note: addresses and port numbers are in host byte order
//////////////////////////////////////////////////////////
class inetaddr: public sockAddr, public sockaddr_in {
public:
enum {
any_addr = INADDR_ANY,
loopback = INADDR_LOOPBACK,
broadcast = INADDR_BROADCAST,
none_addr = INADDR_NONE
};
virtual ~inetaddr() {}
// local host socket address
explicit inetaddr( int portno = 0 )
{ sin_family = AF_INET; host(any_addr); port(portno); }
// remote host address or 'broadcast' or 'loopback'
explicit inetaddr( unsigned long addr, int portno )
{ sin_family = AF_INET; host(addr); port(portno); }
// remote host named address
explicit inetaddr( const char* hostn, int portno )
{ sockInit(); sin_family = AF_INET; host(hostn); port(portno); }
// local(addr=any_addr) or remote service
explicit inetaddr( unsigned long addr, const char* service, const char* proto="tcp" )
{ sockInit(); sin_family = AF_INET; host(addr); port( service, proto ); }
// remote service
explicit inetaddr( const char* hostn, const char* service, const char* proto="tcp" )
{ sockInit(); sin_family = AF_INET; host(hostn); port( service, proto ); }
inetaddr( const inetaddr &ia )
{
sin_family = AF_INET;
if( ia.isValid() )
{
sin_addr.s_addr = ia.addr_in()->sin_addr.s_addr;
sin_port = ia.addr_in()->sin_port;
}
else
{
sin_port = (unsigned short)-1; sin_addr.s_addr = any_addr;
}
}
operator void*() const { return addr_in(); }
sockaddr_in* addr_in() const { return (sockaddr_in*)this; }
int size() const { return sizeof(sockaddr_in); }
int family() const { return sin_family; }
sockaddr* addr() const {return (sockaddr*) addr_in(); }
bool isValid() const { return (sin_family == AF_INET) && (sin_port != (unsigned short)-1); }
unsigned long hostaddr() const { return ntohl(sin_addr.s_addr);}
int port() const { return ntohs(sin_port); }
inetaddr& port( int portno ) { sin_port = htons(portno); return *this;}
inetaddr& port( const char* service, const char* proto = "tcp" )
{
servent *sp = ::getservbyname( service, proto );
sin_port = sp?sp->s_port:-1;
return *this;
}
const char* host() const {
static char hn[64];
hn[0] = '\0';
if( isValid() )
{
switch( sin_addr.s_addr ){
case any_addr: ::gethostname(hn, sizeof(hn)-1); return hn;
case loopback: ::strcpy( hn, "loopback" ); return hn;
case broadcast: :: strcpy( hn, "broadcast" ); return hn;
}
hostent *hp = ::gethostbyaddr( (const char*)&sin_addr, sizeof(sin_addr),sin_family );
if( hp && hp->h_name ) return hp->h_name;
char*hs = inet_ntoa(sin_addr);
if( hs ) return hs;
}
return hn;
}
inetaddr& host( unsigned long addr ) { sin_addr.s_addr = addr; return *this;}
inetaddr& host( const char* hostn )
{
sin_addr.s_addr = ::inet_addr( hostn );
if( sin_addr.s_addr == 0xFFFFFFFF )
{
hostent *hp = ::gethostbyname( hostn );
if( hp )
::memcpy( &sin_addr.s_addr, hp->h_addr, hp->h_length );
else
sin_addr.s_addr = 0xFFFFFFFF;
}
return *this;
}
};
class basic_socket {
#undef _e
#define _e char
public:
typedef basic_socket _Myt;
typedef int int_type;
typedef int pos_type;
typedef int off_type;
friend class myst;
// CONSTANT DEFINITION
// socket stream types (see sockstream type tbl below)
enum socktype {
invalid_type,
inet_stream, tcp = inet_stream,
inet_dgram, udp = inet_dgram,
inet_icmp, icmp = inet_icmp,
inet_raw, raw = inet_raw,
unix_stream,
unix_dgram
};
enum type {
sock_stream = SOCK_STREAM,
sock_dgram = SOCK_DGRAM,
sock_raw = SOCK_RAW,
sock_rdm = SOCK_RDM,
sock_seqpacket = SOCK_SEQPACKET
};
enum sockoption {
so_debug = SO_DEBUG,
so_reuseaddr = SO_REUSEADDR,
so_keepalive = SO_KEEPALIVE,
so_dontroute = SO_DONTROUTE,
sobufroadcast = SO_BROADCAST,
soleninger = SO_LINGER,
so_oobinline = SO_OOBINLINE,
so_sndbuf = SO_SNDBUF,
so_rcvbuf = SO_RCVBUF,
so_error = SO_ERROR,
so_type = SO_TYPE
};
enum { somaxconn = SOMAXCONN };
enum level {
sol_socket = SOL_SOCKET
};
enum shuthow {
shut_read,
shut_write,
shutbufoth
};
// infinite time out limit and error code result
enum {
infinite = -1,
invalid = -1
};
// default and minimal buffer size
enum bufsize{
minbsize = 0,
defaultsize = 1024,
maxbsize = 65536
};
struct socklinger
{
int l_onoff; // option on/off
int lleninger; // linger time
socklinger (int a, int b): l_onoff (a), lleninger (b) {}
};
struct desc
{
SOCKET sock;
explicit desc( SOCKET s ) : sock(s) {}
};
// CONSTRUCTORS
// default constructor
basic_socket(): s(0), _tmo(false) {}
// socket buf copy initializer
basic_socket( const _Myt &sr ): _tmo(false)
{
if( s = sr.sharedSocket() ) s->refcnt++;
}
// low level socket buf constructor
basic_socket( int file, type _t, int _p,
ios::openmode m = ios::in|ios::out ) : _tmo(false)
{
sockInit(); s = new shared( ::socket( file, _t, _p), m );
}
// The constructor you should use
explicit basic_socket( socktype st,
ios::openmode m = ios::in|ios::out ) : _tmo(false)
{
const streamTypeDef &sd = getStreamType( st );
bool connected = (st == _Myt::udp)||(st == _Myt::icmp)||(st == _Myt::raw);
sockInit();
s = new shared( ::socket( sd.family, sd.type, sd.protocol ), m, connected );
}
// socket constructor using descriptor (used with accept)
basic_socket( const desc &_D,
ios::openmode m = ios::in|ios::out ) : _tmo(false)
{
s = new shared( _D.sock, m, _D.sock != _Myt::invalid );
}
// socket destructor
virtual ~basic_socket()
{
if( s && !--s->refcnt ) delete s;
}
_Myt& operator= ( const _Myt& sr )
{
if( s != sr.sharedSocket() && s && !--s->refcnt ) delete s;
if( s = sr.sharedSocket() ) s->refcnt++;
_tmo = 0;
return *this;
}
// UTILITY OPERATIONS
#ifdef WIN32
int errnum() const { return ::WSAGetLastError();}
#else
int errnum() const { return ::errno;}
#endif
bool timeout() const { return _tmo; }
bool isValid() const { return s && s->sock != _Myt::invalid; }
SOCKET sd() const { return s ? s->sock : _Myt::invalid; }
int sendtimeout( int msec ){ return s ? s->sendtimeout(msec) : _Myt::infinite; }
int recvtimeout( int msec ){ return s ? s->recvtimeout(msec) : _Myt::infinite; }
bool is_open( ios::openmode m = shared::open ) const
{ return s?(s->state&shared::open&m)!=0: false; }
// SOCKET OPERATIONS
bool listen( int _n = _Myt::somaxconn )
{
return ::listen( sd(), _n ) != _Myt::invalid;
}
bool bind( const sockAddr &sa )
{
return ::bind( sd(), sa.addr(), sa.size() ) != _Myt::invalid;
}
bool connect( const sockAddr &sa )
{
bool buf = ::connect( sd(), sa.addr(), sa.size() ) != _Myt::invalid;
if( buf ) s->state |= shared::open;
return buf;
}
_Myt::desc accept( const sockAddr &sa )
{
int len = sa.size();
return _Myt::desc(::accept( sd(), sa.addr(), &len ));
}
_Myt::desc accept()
{
return _Myt::desc(::accept( sd(), 0, 0 ) );
}
bool is_readready( int msec )
{
return s ? s->is_readready( msec, _tmo ) : false;
}
bool is_writeready( int msec )
{
return s ? s->is_writeready( msec, _tmo ) : false;
}
bool is_exceptionpending( int msec )
{
return s ? s->is_exceptionpending( msec, _tmo ) : false;
}
// DATA TRANSMISSION
// return number of received elements
// return 0 on error, timeout or connection closed or partial char received.
// Use is_open() or timeout() or errnum() to findout.
int_type recv( _e* buf, int_type len, int file = 0 )
{
return s ? s->recv( _tmo, buf, len, file ) : 0;
}
// return number of received elements
// return 0 on error, timeout or connection closed.
// Use is_open() or timeout() or errnum() to findout.
int_type recv( sockAddr &sa, _e* buf, int_type len, int file = 0 )
{
return s ? s->recv( _tmo, sa, buf, len, file ) : 0;
}
// return true if len elements have been received
// return false on error, timeout, connection closed or partial char received.
// Use is_open() or timeout() or errnum() to findout.
bool recvAll( _e* buf, int_type len, int file = 0 )
{
return s ? s->recvAll( _tmo, buf, len, file ) : false;
}
// return number of sent elements,
// this number is less than len on error, timeout or connection closed
// Use is_open() or timeout() or errnum() to findout.
int_type send( _e* buf, int_type len, int file = 0 )
{
return s ? s->send( _tmo, buf, len, file ) : 0;
}
// return number of sent elements,
// this number is less than len on error, timeout or connection closed
// Use is_open() or timeout() or errnum() to findout.
int_type send( sockAddr &sa, _e* buf, int_type len, int file = 0 )
{
return s ? s->send( _tmo, sa, buf, len, file ) : 0;
}
// returns the number of bytes read
int_type read( _e *buf, int_type len )
{
return recv( buf, len );
}
// returns the number of bytes written
int_type write( _e *buf, streamsize len )
{
return send( buf, len );
}
// set input and output buffer size (0 == none)
int_type setinputbuf( int_type sz )
{
return s ? s->setinputbuf( sz ) : 0;
}
int_type setoutputbuf( int_type sz )
{
return s ? s->setoutputbuf( sz ) : 0;
}
// get input and output buffer size
int_type getinputbufsize()
{
return s ? s->isz : 0;
}
int_type getoutputbufsize()
{
return s ? s->osz : 0;
}
// OBSERVER METHODS
// return peer address
bool peer( sockAddr &sa )
{
int len = sa.size();
return s ? (::getpeername( s->sock, sa.addr(), &len ) != _Myt::invalid ) : false;
}
// return local address
bool local( sockAddr &sa )
{
int len = sa.size();
return s ? (::getsockname( s->sock, sa.addr(), &len ) != _Myt::invalid ) : false;
}
// return number of elements available
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -