The abstract base class

class SWBaseSocket
Constructor
enum base_error
class SWBaseError
enum block_type
listen()
accept()
disconnect()
close_fd()
send()
sendmsg()
recv()
recvmsg()
fsend()
fsendmsg()
frecv()
get_fd()
get_host()
get_peer()
set_timeout()
print_error()
get_error()
Typical Use
Server side example
Client side example
Additional Datatypes


SWBaseSocket

This is the abstract base class for all socket classes in SocketW. You can't use this class directly but every derived class must implement the methods in this class.

Constructor:
SWBaseSocket()
Abstract constructor.

Methods and datatypes:
enum base_error{ok, fatal, notReady, portInUse, notConnected, msgTooLong, terminated, noResponse, timeout, interrupted}
The possible error types for this class (and derived classes), see "Error handling" for more information.
class SWBaseError
The SWBaseError class is defined here.

enum block_type{blocking, noWait, nonblocking}
Used in derived classes constructors to set the blocking behaviour of the class:
virtual bool listen(int qLimit = 5, SWBaseError *error = NULL)
Make the socket listen for connections. To accept connections a socket must first be binded to a local address and then a willingness to accept incoming connections must be specified with listen(), and then the connections are accepted with accept(). The optional qLimit argument defines the maximum length the queue of pending connections may grow to. Returns true on success. Possible error types: portInUse, notConnected and fatal.

virtual SWBaseSocket* accept(SWBaseError *error = NULL)
Accept an incoming connection. Returns a new socket class connected with the peer or NULL on failure. You can cast the class to the correct type if you need to (e.g. (SWInetSocket *)mysocket). If there is no incoming connection accept() will block until there is one (if not in nonblocking mode). The returned class should be freed with delete when not needed any longer. Possible error types: notReady, notConnected, interrupted, timeout and fatal.

virtual bool disconnect(SWBaseError *error = NULL)
Do the disconnect ritual (signal peer, wait for close signal and then close socket). Returns true on success. Possible error types: notConnected, notReady, interrupted, timeout, noResponse and fatal.

virtual bool close_fd()
Closes the socket without waiting for the remote peer. Use with care, disconnect() is cleaner. Returns false if the socket already is closed.

virtual int send(const char *buf, int bytes, SWBaseError *error = NULL)
Transmit at most the specified number of bytes of "buf" to remote peer. On most systems "bytes" will be the exact number of bytes transmitted if using a blocking socket but some systems might transmit less. If using a nonblocking socket, most systems will however return before the full amount of bytes have been transmitted if it must block (e.g. wait for a buffer) to transmit the remaining bytes (will indicate notReady in that case). Returns the actual amount of bytes sent or -1 on failure. Possible error types: notConnected, notReady, interrupted, timeout, msgTooLong, fatal and terminated.

virtual int sendmsg(const std::string msg, SWBaseError *error = NULL)
Same as send() but with a std::string instead.

virtual int recv(char *buf, int bytes, SWBaseError *error = NULL)
Receive at most the specified number of bytes and place them in "buf". This means that recv() fetch any data available, up to the requested amount, rather than waiting for the full amount requested. If no data is available, recv() waits until there is (or returns notReady if using a nonblocking socket). You should try to receive as much data as possible every time so no data is discarded (data might be discarded if you leave to much data waiting in the system buffer). Returns the actual amount of bytes received or -1 on failure and 0 if terminated. Possible error types: notConnected, notReady, interrupted, timeout, terminated, fatal and noResponse.

virtual std::string recvmsg(int bytes = 256, SWBaseError *error = NULL)
Same as recv() but the received data will be copied to the returned std::string. The returned string will be empty on failure.

virtual int fsend(const char *buf, int bytes, SWBaseError *error = NULL)
If using a blocking socket this method should work just as send(). If using the noWait or nonblocking mode then this method might have some advantages over using send() directly. Anyway, this method makes sure that the exact number of bytes specified are sent. In nonblocking mode this method will return with notReady just as send() but will handle the "buf" pointer itself, i.e. you must call this method with exactly the same arguments until all data is sent unlike send() where you must recalculate the arguments every call. Returns "bytes" when finished or a negative integer on failure. If the error type returned is notReady then the returned failure value is the amount of bytes sent so far but negated. The same error types as send().

virtual int fsendmsg(const std::string msg, SWBaseError *error = NULL)
Same as fsend() but with a std::string instead. Unlike sendmsg() there is no need to reformat the string on notReady before repeating the call.

virtual int frecv(char *buf, int bytes, SWBaseError *error = NULL)
Same as recv() but the exact number of bytes specified are received. In noWait or nonblocking mode notReady is returned if not enough data is available and then the method must be called again with exactly the same arguments (i.e. the "buf" pointer should not be recalculated). Be sure that the remote peer really is going to send at least the specified number of bytes or you might trying to receive bytes that will never be sent. Returns "bytes" when finished, 0 if terminated and a negative integer on failure. If the error type returned is notReady then the returned failure value is the amount of bytes sent so far but negated. The same error types as recv().

virtual int get_fd(SWBaseError *error)
Get the socket descriptor. Can for example be used with select(). Returns -1 on failure. Possible error types: notConnected.

virtual bool get_host(sockaddr *host, SWBaseError *error = NULL)
Fills the provided sockaddr structure with info about the local host. See man unix(7) or ip(7) for more information about the structure. Returns true on success. Possible error types: fatal and notConnected.

virtual bool get_peer(sockaddr *peer, SWBaseError *error = NULL)
Fills the provided sockaddr structure with info about the remote peer. See man unix(7) or ip(7) for more information about the structure. Returns true on success. Possible error types: fatal and notConnected.

void set_timeout(Uint32 sec, Uint32 usec)
Sets the timeout value in seconds and microseconds. Used in blocking mode when a method waits for data. This affects the methods with a timeout error type. Doing set_timeout(0,0) means wait forever (default). No errors possible.

virtual void print_error()
Prints the last error if any as a human readable message to stderr.

virtual std::string get_error()
Returns the last error as a human readable message. The returned string is empty if the last method call didn't fail.


Typical Use

Sockets are typically used in two ways; server side or client side. The server side starts with binding (bind()) to a local address where it will be listening for incoming connections from the client side. Then the willingness to accept incoming connections must be specified with listen(), and finally incoming connections are accepted with accept(). A new socket connected to the client is created when accepting an incoming connection. The original socket (the listener) can be used to accept more connections and is not itself connected to any client.

The client side only needs to connect() to the server side. The connected socket can then be used to transfer data to and from the server.

Server side example:

#include "SocketW.h"
...
SWInetSocket listener;
SWInetSocket *mySocket;

listener.bind(...);  // bind() is implemented in derived classes
listener.listen();

mySocket = (SWInetSocket *)listener.accept();

// do something with mySocket...
mySocket->sendmsg("Hello Client!");

// disconnect and clean up
mySocket->disconnect();
delete mySocket;



Client side example:

#include "SocketW.h"
...
SWInetSocket mySocket;

mySocket.connect(...);  // connect() is implemented in derived classes

// do something with mySocket...
string msg = mySocket.recvmsg();

// disconnect
mySocket.disconnect();


Additional Datatypes

SocketW has some additional datatypes that can be practical to use when it is important to know the exact size of the data you're working with. These datatypes are guaranteed to be the correct size (this is checked when SocketW is compiled). These are the same datatypes as used in libSDL so make sure to include "SDL.h" before "SocketW.h" to avoid double definitions if you use SocketW with SDL.





Copyright © 2003 Anders Lindström
Last updated 031025