classCSocket
{ enum State { Disconnected, Bound, Listening, Connected };CSocket ();
CSocket ( int fd, CSocket::State state );
const int getSocketFd ();
const CSocket::State getState ();
void Connect (const std::string& host, const std::string& service);
void Connect( unsigned long int IpAddress, unsigned short service);
void Bind (const std::string& service);
void Listen ( unsigned int nBacklog = );
CSocket* Accept ( std::string& client);
void Shutdown ();
int Read ( void* pBuffer, size_t nBytes);
int Write (const void* pBuffer, size_t nBytes);
void getPeer ( unsigned short& port, std::string& peer);
void OOBInline ( bool State = TRUE);
bool isOOBInline ();
void setRcvLowWaterMark ( size_t nBytes);
void setSndLowWaterMark ( size_t nBytes);
size_t getSndLowWaterMark ();
void setRcvTimeout ( unsigned int nMs);
unsigned int getRcvTimeout ();
void setSndTimeout ( unsigned int nMs);
unsigned int getSndTimeout ();
void Debug ( bool fState = TRUE);
bool isDebug ();
void SetNotRoutable ( bool fRoutable = TRUE);
bool isNotRoutable ();
void setSndBufSize ( size_t nBufferSize);
size_t getSndBufSize ();
void setRcvBufSize( size_t nBytes);
size_t getRcvBufSize();
void setLinger( bool lOn, int nLingerSeconds);
void getLinger( bool& isLingering, int& nLingerSeconds);
static std::string StateName( CSocket::State state);
void Flush();
};
This class encapsulates file descriptors that are open on
BSD sockets. The package supports client sockets, servers sockets
and encapsulating sockets that were opened via the
socket(2)
system call.
Client sockets normally construct, then connect and transfer data.
Server sockets construct, bind to a server port, listen for connections
and the accept connections creating a new data transfer socket.
File descriptors that are opened on sockets can be wrapped in a
CSocket
object. Once wrapped the object
can be treated as if it was constructed "normally".
CSocket
objects are stateful. The
state of an object is one of the values defined by the
CSocket::State enum (See DATA TYPES below). The set of methods that
can be legally invoked depends on the socket state. For each method
described in METHODS below, we will indicate the state
restrictions. If a method is invoked in a forbidden state,
CTCPBadSocketState
is thrown.
CSocket
();
Constructs a new object. The object starts out life in the CSocket::Disconnected state.
CSocket
( int fd, CSocket::State state );
This constructor wraps the socket file descriptor;
fd
in a CSocket
object. The state
parameter
describes the state.
It is important that you supply the correct
state
value to the constructor
so that the object knows which methods are legal when.
const int
getSocketFd
();
Returns the value of the file descriptor for the underlying socket.
const CSocket::State
getState
();
Returns the current state of the socket.
void
Connect
(const std::string& host, const std::string& service);
Connects the socket as a client to a service port.
The host
parameter can be either
a DNS host name string (e.g. "spdaq20.nscl.msu.edu") or
a dotted IP address (e.g. "35.9.56.50"). The
swervice
is either a named service
(from e.g. /etc/services in the peer) or a service number
(e.g. "30000").
You can only call this method if the socket is in the CSocket::Disconnected state. If successful the socket is then in the CSocket::Connected state.
void Connect( unsigned long int IpAddress, unsigned short service);
Connects the socket to a server. IpAddress
is the IP address of the server system in host
byte order. service
is the service
port number in host
byte order.
You can only call this method if the socket is in the CSocket::Disconnected state. If successful the socket is then in the CSocket::Connected state.
void
Bind
(const std::string& service);
Binds the socket to a service port. This makes the
object a server socket. service
is either the name of a service (e.g. in
/etc/services) or a service number
(e.g. "30000").
This method must be called with the socket in the CSocket::Disconnected state and, if successful, will put the socket in the CSocket::Bound state.
void
Listen
( unsigned int nBacklog = );
Establishes a queue to accept connections on a server
socket. nBacklog
is the number
of un-accepted connection requests that can be
pending at any given time.
If a
a connection is requested when the listen queue is full, it
is refused or allowed to retry depending on the protocol
(according to linux man connect(2)).
The socket must be in the CSocket::Bound state. On successful completion, the socket is put in the CSocket::Listening state.
CSocket*
Accept
( std::string& client);
Used by a server socket in the CSocket::Listening state to accept the next connection on the connection backlog queue. If there is no pending connection, this method will block until one is available.
The return value is a pointer to a CSocket
in the CSocket::Connected state with
which the server can exchange data with the client.
Additionally the client
parameter
is filled in with information about the host. If
the hostname can be determined via reverse DNS lookup,
the fully qualified host name is stored. If not, the
dotted IP address string is stored.
This method does not change the state of the object.
If you want to avoid blocking when there are no
connections present in the backlog queue you can
use getSocketFd
to get the
underlying socket's file descriptor and use it in either
a poll(2)
or select(2)
system service testing for readability. The file descriptor
will be considered readable when a connection is present
on the backlog.
void
Shutdown
();
Shuts down a socket that is in the CSocket::Connected state. The socket is still usable but:
The socket is in the CSocket::Disconnected state
Any attempts by the peer to transfer data to the socket will fail.
Any attempts by the peer to transfer data from the socket will only work as long as there is unconsumed data in the internal TCP/IP buffers for the file descriptor.
Note that this method invalidates any file descriptor
the application may have cached via a call to
getSocketFd
. Such file descriptors
must be re-fetched.
int
Read
( void* pBuffer, size_t nBytes);
Reads data from the socket. The socket must be in the
CSocket::Connected state.
pBuffer
points to a buffer into which
the read data will be received. nBytes
is the desired number of bytes to read. Normally if there
are no bytes to read, this method will block until the
read can be satisfied.
The method returns the number of bytes actually read.
Note that this may be less than the number of bytes
requested with nBytes
.
Several exceptions can be thrown besides
CTCPBadSocketState:
:
CErrnoException
- if the
underlying read(2)
completed
with an error. The socket is placed in the
CSocket::Disconnected state.
CTCPConnectionLost
- if
the peer shutdown the socket or is no longer
communicating for some other reason (program exit
or system failure). The socket is shutdown
and placed in the CSocket::Disconnected
state.
int
Write
(const void* pBuffer, size_t nBytes);
Writes data to the peer over the socket.
pBuffer
points to the data to write
and nBytes
is the number of bytes
of data to write. The return value is the number of
bytes of data actually written which, on success, is
always nBytes
. If there are non-fatal
errors like EAGAIN, EINTR
or EWOULDBLOCK, method will attempt
to write the unwritten parts of the buffer.
Exceptions can be thrown as follows:
CTCPBadSocketState
-
The socket is not in the
CSocket::Connected state.
CTCPConnectionLost
- the
connection with the peer was lost and therefore
future writes would also fail. The socket
is placed in the CSocket::Disconnected
state.
CErrnoException
- some error
was reported via errno
. The socket
is placed in the
CSocket::Disconnected state.
void
getPeer
( unsigned short& port, std::string& peer);
Fetches information about the peer of a
CSocket::Connected socket.
port
is filled in with the port to which
this port is connected. peer
is filled in with either the fully qualfied domain
name fo the hsot the peer runs on (if a reverse DNS
lookup can be performed) or the dotted IP adress in
string form if not.
void
OOBInline
( bool State = TRUE);
Can be called when the socket is in any state except
CState::Open Sets the
SO_OOBINLINE parameter of the socket.
If State
is true,
out of band data is included inline with the socket data.
If false out of band data is not inline.
bool
isOOBInline
();
Returns true if out of band data are inline else false.
void
setRcvLowWaterMark
( size_t nBytes);
Sets the receive low water mark to nBytes
.
This value is the number of bytes that must have been
buffered at the protocol level before data are returned
to the caller.
Some operating systems don't actually allow this to be
modified but silently do nothing. To detect if this
state you can use getRcvLowWaterMark
can be invoked to see what the current low water mark
is.
void
setSndLowWaterMark
( size_t nBytes);
Sets the low watermark of the send buffer.
nBytes
is the minimum number
of bytes that must be buffered before the protocol starts
emitting data.
size_t
getSndLowWaterMark
();
Returns the receive low watermark value. This is the actual value which may differ from the value set.
void
setRcvTimeout
( unsigned int nMs);
Sets the receive buffering timeout to
nMs
milliseconds. With
a large receive low water mark, there is a chance
that for reads lower than the watermark, if data
are only being slowly received, reads could block
for a long time or even forever waiting for the
watermark to be hit. The receive timeout limits
how long a read can be blocked when there is buffered
data but fewer than the number of bytes in the receive
low water mark.
unsigned int
getRcvTimeout
();
Returns the value of the receive timeout.
void
setSndTimeout
( unsigned int nMs);
Sets the value of the send timeout to nMs
milliseconds. When the first bytes are written to the
internal protocol buffers, a timer is started. Data
are only written on the wire to the peer when either
the send low watermark is achieved or the timer expires.
This timeout ensures that data are eventually
queued for write to the
peer with a maximum host side latencey of nMs
milliseconds even if the data are being buffered quite
slowly or the send low watermark is never achieved.
unsigned int
getSndTimeout
();
Returns the number of milliseconds in the send timeout.
void
Debug
( bool fState = TRUE);
Only programs with the effective user id of root can
perform this operation (CErrnoException
is thrown if otherwise). Setting this causes the system
to produce debugging KERN_LOG messages
which syslog can be configured to put into some log file
for later analysis.
bool
isDebug
();
Returns true if socket debugging is enabled. false if not.
void
SetNotRoutable
( bool fRoutable = TRUE);
If fRoutable
is true
routing is turned off for the packets from this protocol.
If fRoutable
is false,
routing is enabled.
Non routed messages will not be sent through gateways/routers. This confines them to the subnet local to the sender. To turn off routing on socket messages:
You should probably turn off routing on both sides.
You need to have a very good understanding of the network physical topology (what a subnet is and where your peer is relative to you).
bool
isNotRoutable
();
Returns the state of the non-routing flag. true means routing is off for this socket while false means it is on.
void
setSndBufSize
( size_t nBufferSize);
Sets the total size of the send buffer for the socket
to nBufferSize
. This is different
from the low watermark. This determines the number of bytes
of data that are buffered in the local machine while the
peer has halted transmission via flow control. This
buffering allows the application to continue to queue
data for transmission without blocking until the buffer
is full.
size_t
getSndBufSize
();
Returns the number of bytes in the socket's send buffer.
void setRcvBufSize( size_t nBytes);
Sets the receive buffer size for the socket
to nBytes
.
This is the number of received bytes the local host
will buffer prior to exerting flow control on the
peer to get it to slow down or stop transmitting.
This buffer allows the local host to continue to receive
data between reads of data at the application level.
size_t getRcvBufSize();
Returns the number of bytes of data in the receive buffer.
void setLinger( bool lOn, int nLingerSeconds);
The termination of a TCP/IP connection is a dance that requires cooperation from both parties to proceed properly. Best practices require the client to close the connection and the server, on detecting this to be the case, to close its side of the connection. When this is not done, connections can sit in the TIME_WAIT state for some time (the linger timeout)
This call allows the application to enable or disable
lingering (the lOn
parameter) and
to set the linger timeout
(nLingerSeconds
).
Note that in general if you have to modify the default parameters your application protocol is probably not following TCP/IP best practices.
One case that may warrant it is when the server detects a misbehaving client and may want to abortively close the connection. In that case the linger timeout can be set to zero or lingering turned off in order to avoid hanging the connection in TIME_WAIT.
void getLinger( bool& isLingering, int& nLingerSeconds);
Sets isLingering
to the
state of the socket's lingering flat and
nLingerSeconds
to the linger
timeout.
static std::string StateName( CSocket::State state);
Given a socket state value returns a string that represents that state. This is used in generating user readable messages that must include the state.
void Flush();
Reads and discards all data buffered fro iput on the socket.
The CSocket::State data type is exported as public. This type is an enum that represents a socket state. It is defined as follows: