Moby Disk's Cross Platform API Reference

[ThreadAPI]   [SockAPI]   [MemAPI]   [PipeAPI]   [ServerAPI]

This library includes basic to advanced functionality for creating cross-platform client and server software. For anyone beginning to create network applications, I suggest starting with just the SockAPI and using the rest if you need them.


ThreadAPI: class Threadable

   The threadable class allows the creation of child processes that execute independantly of the main process. The management of the child is completely transparent. Just start it, and it goes. Successful porting of this library requires adherence to the rules listed below, due to cross-platform limitations.

Usage of Threadable

  1. Extend the Threadable class to create your main() function:
    class MyThread : public Threadable {
      public:
        MyThread(myParms) { ... }    // Your constructor
        virtual void main() { ... }  // Your main
    };
    
  2. Construct/Call the thread:
    EXAMPLE 1:
    void main() {
      Threadable::init();
      MyThread *child = new MyThread();
      child->spawn();
      delete child;      // WRONG!! Threadable deletes when appropriate!
      Threadable::done();
    }
    EXAMPLE 2:
    void main() {
      Threadable::init();
      MyThread child();  // WRONG!! Declare as a pointer or C++ will attempt
                         // to delete the Threadable!!
      child.spawn();
      Threadable::done();
    }
    
  3. Rules governing threads

    1. The Threadable main() function may not read or write variables outside its class instance.
    2. The Threadable object must be declared as a pointer and never deleted.
      (either explicitly by the program, or automatically by the language)
    3. Threadable::init and Threadable::done must be called at the beginning and ending part of the main process.
    4. Threads can spawn other threads. (I think, haven't tried it)

SockAPI: class Socket

   This class allows anyone to easily create network applications without dealing with the low-level BSD socket calls. I find it a better option than the complex, proprietrary, and inefficient CSocket functions offered by MFC. This compiles under VC 5.0 and should work on all machines supporting BSD sockets. I have not compiled recent revisions to see how compatible this is.

A basic understanding of networking would be very helpful here, but not necessary. Perhaps just knowing what you want to do will be enough. Minimal C++ knowledge is a must. For decent examples, both my WebDog and Netsuite programs make use of this library.

Usage of Socket - Client Side

The example below will connect to www.yahoo.com and request index.html. Basically, this is a miniature web browser. It serves as a reasonable example of the Socket library. For good examples, look at WebDog or Netsuite at here
#include "Socket.h"  // Socket library
#define HTTP_PORT 80 // Port for web server

void main() {
  Socket::init();

  Socket sock;                                         // Create a socket
  sock.connect("www.yahoo.com",HTTP_PORT);             // Connect to Yahoo!

/* If connection is successful, request index.html
   from their site.  HTTP request is followed by a
   blank line to mark end of request. */

  if (sock.isConnected()) {
    cout << sock.localName() << " connected to " << sock.peerName()
         << ":" << sock.peerPort() << endl;

    iostream client(&sock);                            // Connect socket to C++ IO stream
    client << "GET /index.html HTTP/1.0" << endl;
    client << endl;

/* Now read Yahoo!'s response and display it on the screen.
   This will include both the HTTP result header and the HTML file. */

    char buffer[512];
    while (!client.eof() && sock.isConnected()) {
      client.read(buffer,sizeof(buffer)-1);
      cout.write(buffer,client.gcount());
    }
  }

  Socket::done();                                      // Shutdown the socket library
}

Understanding the Example Client

The first line of main, Socket::init() initializes the socket library. Do not forget this or magically none of the socket calls will work. Consequently, not calling Socket::done() will cause a mysterious memory leak and potentially leave sockets open.

Next, we create a Socket named sock, which is an unconnected client socket. To connect to a site, we call socket.connect(char *hostname, int port). This connects to the specified server and port combination. The port tells the remote server what protocol we are using. Normally, web based services based on HTTP are on port 80. A list of these can be found at the Internet Assigned Numbers Authority or by asking someone who knows more than you.

Okay, now we make sure we are connected by calling sock.isConnected(). If we are, we now construct a typical C++ IO stream with the socket by creating an iostream named client with iostream client(streambuf *streamb). Now we can use standard C++ functions and operators such as read, write, << and >>, getline, etc. with the socket. If you are not familiar with these, learn them, they are the first C++ thing you should know.

Now we cheer by outputting a successful connection message. This will tell us our name, the remote name, and the port the remote is using to talk to us. Then we send the HTTP header. This is basically a GET with the filename we wish to get. This is part of HTTP and is not particularly important here.

Once the header is sent, the remote site will respond. We allocate a 512 byte buffer and display the response on screen. This is done with the client.read() and cout.write() calls. This is standard C++ style IO. Noteworthy is the while loop which checks for !client.eof() && sock.isConnected(). In this scenario, it is possible for the remote to abruptly disconnect(network error, modem hangup) so we must accomodate this possibility as well as eof().

When we are done, we simply call Socket::done. This will automatically shut down and close our socket. If we were to do another connection, we would call sock.close().

Usage of Socket - Server side

Writing servers using the Socket API is also simple. The same principles a apply, except that instead of connecting with sock.connect() we wait on a connection. To build a powerful server implies use of multithreading which is not included here.
#include "SockAPI.h"
#include <string.h>
#define SERVER_PORT 5050             // Listen on this port

void main() {
  Socket::init();

  Socket serverSock(SERVER_PORT);      // Create a socket for the server on this port
  Socket *clientSock;                  // Create a socket for the client
  char   name[256];

  serverSock.listen();                 // Servers listen on sockets
  while (1) {                          // Our server runs forever// Wait for a connection
    iostream client(clientSock);       // Create iostream to client

/* Begin server processing here.  We have a socket and an
iostream.  From here on this is basically console IO. */

    client << "Enter your name now:" << endl;
    client >> name;

    if (strcmpi(name,"Moby Disk") == 0)
      client << "Welcome to my server!" << endl;
    else
      client << "Go away you bum!" << endl;

    delete clientSock;                 // Cleanup the client socket
  }

  Socket::done();                      // In case we ever got here...
}

Understanding the Example Server

This client could be tested by issuing a telnet to port 5050 on the host machine. The user would then receive a prompt to enter their name, and a validation response. After this, the server immediately disconnects and waits for another connection.

This is structurally different from the client end, but few new Socket calls are required. We start by creating TWO sockets: one for the server, and one for the client currently engaged in conversation. serverSock is constructed differently from before by calling the constructor Socket(int port) This creates an unconnected server socket bound to the specified port. I choose port 5050 randomly.

Before the server enters its loop, we call serverSock.listen(). This tells the socket to listen on the specified port.

After we enter the loop, the server calls Socket *serverSock.accept(). The server is now blocked, waiting on a connection. Once a connect request is received, the function will return a pointer to a client Socket. The server must explicitly delete this pointer or the connection may remain open, and eat system resources.

The returned Socket is then used to create a C++ IO stream as before, and the server carries out is work. When the server is done, it deletes the client socket and loops. The IO stream is automatically deleted at each iteration of loop simply by declaring it inside the loop.

Socket API Summary

This should be sufficient information to begin coding something slick. Be sure you send it to me and give me complaints, suggestions, love, money, etc. A cleanly web formatted version of the SockAPI.h is available here.

MemAPI

Allows shared memory use in Windows and UNIX platforms. I created this for a project that no longer exists, and no ducmentation exists. If you want it, let me know.

PipeAPI

Allows use of threadable pipes in Windows and UNIX platforms. I created this for a project that no longer exists, and no ducmentation exists. If you want it, let me know.

ServerAPI

This is currently used by my Netsuite program and an SQL Server front end I created for Protologics Corporation. It has built in server functionality allowing the designer to simply derive a class and provide minimal functionality for client processing. It uses the ThreadAPI and SockAPI described above and is heavily C++ oriented. This has never been 'split' from the projects using it, and should anyone request it I will make it available.