title: How to implement a recv() callback
body: <p>I'm trying to improve my knowledge of OOP and decided to create a simple class to simplify sockets programming.
  This is a learning experiment so I do not want to use boost, or other libraries.</p>
  
  <p>I want to implement an <em>event-driven</em> recv(). Meaning, everytime there is new data coming in, it should call my function.</p>
  
  <p>I think I need to create a thread to run a recv() loop and then call my function everytime there is new data. Is there other way around using threads? I want my code to be portable.</p>
  
  <p>Here is my simple Class and example code:</p>
  
  <p><strong>class.h:</strong></p>
  
  <pre><code>#ifndef _SOCKETSCLASS_H
  #define _SOCKETSCLASS_H
  
  #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) &amp;&amp; !defined(__CYGWIN__)
      #define W32
      #include &lt;WinSock2.h&gt;
      #pragma comment(lib, "ws2_32.lib")
  #else
      #include &lt;sys/socket.h&gt;
      #include &lt;arpa/inet.h&gt;
      #include &lt;netdb.h&gt;
  
      #define SOCKET int
  #endif
  #include &lt;string&gt;
  #include&lt;ctime&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdarg.h&gt;
  #include &lt;varargs.h&gt;
  #include &lt;tchar.h&gt;
  
  using namespace std;
  
  #ifdef _DEBUG
      #define DEBUG(msg) XTrace(msg)
  #else
      #define DEBUG(msg, params)
  #endif
  
  struct TCP_Client_opts
  {
      BOOL    UseSCprotocol;
      BOOL    UseEncryption;
      BOOL    UseCompression;
      int     CompressionLevel;
      void    *Callback;
      BOOL    async;
  };
  
  struct TCP_Stats
  {
      unsigned long int   upload; //bytes
      unsigned long int   download;//bytes
      time_t              uptime; //seconds
  };
  
  class TCP_Client
  {
      public:
          TCP_Client();
          TCP_Client(TCP_Client_opts opts_set);
          ~TCP_Client();
          SOCKET          GetSocket();
          void            SetOptions(TCP_Client_opts opts_set);
          TCP_Client_opts GetOptions();
          BOOL            Connect(string server, int port);
          int             Send(string data);
          int             Recv(string *data);
          BOOL            IsConnected();
          int             Disconnect();
          TCP_Stats       GetStats();
      private:
          SOCKET          s = SOCKET_ERROR;
          TCP_Client_opts opts;
          TCP_Stats       stats;
          BOOL            connected = FALSE;
          time_t          starttime;
  };
  #endif
  </code></pre>
  
  <p><strong>class.cpp:</strong></p>
  
  <pre><code>#include "SocketsClass.h"
  
  void XTrace(LPCTSTR lpszFormat, ...)
  {
      va_list args;
      va_start(args, lpszFormat);
      int nBuf;
      TCHAR szBuffer[512]; // get rid of this hard-coded buffer
      nBuf = _vsnwprintf_s(szBuffer, 511, lpszFormat, args);
      ::OutputDebugString(szBuffer);
      va_end(args);
  }
  
  
  TCP_Client::TCP_Client(TCP_Client_opts opts_set)
  {
      SetOptions(opts_set);
  }
  
  TCP_Client::~TCP_Client()
  {
      Disconnect();
  }
  
  TCP_Client::TCP_Client()
  {
  }
  
  void TCP_Client::SetOptions(TCP_Client_opts opts_set)
  {
      opts = opts_set;
  }
  
  TCP_Client_opts TCP_Client::GetOptions()
  {
      return opts;
  }
  
  SOCKET TCP_Client::GetSocket()
  {
      return s;
  }
  
  BOOL TCP_Client::IsConnected()
  {
      return connected;
  }
  
  int TCP_Client::Disconnect()
  {
      connected = FALSE;
      stats.uptime = time(0) - starttime;
      return shutdown(s, 2);
  }
  
  BOOL TCP_Client::Connect(string server, int port)
  {
      struct sockaddr_in RemoteHost;
  
  #ifdef W32
      WSADATA       wsd;
      if (WSAStartup(MAKEWORD(2, 2), &amp;wsd) != 0)
      {
          DEBUG(L"Failed to load Winsock!\n");
          return FALSE;
      }
  #endif
  
      //create socket if it is not already created
      if (s == SOCKET_ERROR)
      {
          //Create socket
          s = socket(AF_INET, SOCK_STREAM, 0);
          if (s == SOCKET_ERROR)
          {
              DEBUG(L"Could not create socket");
              return FALSE;
          }
      }
  
      //setup address structure
      if (inet_addr(server.c_str()) == INADDR_NONE)
      {
          struct hostent *he;
  
          //resolve the hostname, its not an ip address
          if ((he = gethostbyname(server.c_str())) == NULL)
          {
              //gethostbyname failed
              DEBUG(L"gethostbyname() - Failed to resolve hostname\n");
              return FALSE;
          }
      }   
      else//plain ip address
      {
          RemoteHost.sin_addr.s_addr = inet_addr(server.c_str());
      }
  
      RemoteHost.sin_family = AF_INET;
      RemoteHost.sin_port = htons(port);
  
      //Connect to remote server
      if (connect(s, (struct sockaddr *)&amp;RemoteHost, sizeof(RemoteHost)) &lt; 0)
      {
          DEBUG(L"connect() failed");
          return FALSE;
      }
  
      connected = TRUE;
      starttime = time(0);
      stats.download = 0;
      stats.upload = 0;
      return TRUE;
  }
  
  TCP_Stats TCP_Client::GetStats()
  {
      if (connected==TRUE)
          stats.uptime = time(0)-starttime;
      return stats;
  }
  
  int TCP_Client::Send(string data)
  {
      stats.upload += data.length();
      return send(s, data.c_str(), data.length(), 0);
  
  }
  
  int TCP_Client::Recv(string *data)
  {
      int ret = 0;
      char buffer[512];
  
      ret = recv(s, buffer, sizeof(buffer), 0);
      data-&gt;assign(buffer);
      data-&gt;resize(ret);
      stats.download += data-&gt;length();
  
      return ret;
  }
  </code></pre>
  
  <p><strong>main.cpp:</strong></p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include "SocketsClass.h"
  
  using namespace std;
  
  
  int main(int argc, char *argv)
  {
      TCP_Client tc;
      tc.Connect("127.0.0.1", 9999);
      tc.Send("HEllo");
      string data;
      tc.Recv(&amp;data);
      puts(data.c_str());
      tc.Disconnect();
      printf("\n\nDL: %i\nUP: %i\nUptime: %u\n", tc.GetStats().download, tc.GetStats().upload, tc.GetStats().uptime);
      return 0;
  }
  </code></pre>
  
  <p>Some extra questions:</p>
  
  <ol>
  <li>Imagine I'm sending a file. How would my function know that the current data is related to the previous message?</li>
  <li>How is my class design and implementation? SHould I change anything?</li>
  </ol>
  
  <p>Thank you</p>