Using EventMachine in C/C++ Programs

You can use EventMachine as a standalone library to implement high-speed I/O in C/C++ programs.

An example of a simple EventMachine echo server

#include "project.h"

#include <iostream>

using namespace std;

class MyConnection: public EM::Connection {
  public:
  void ReceiveData (const char *data, int length) {
    cout << data;
    this->SendData(data, length);
  }
  
  void PostInit() {
    cout << "Post Init\n";
  }
  
  void Unbind() {
    cout << "Unbind\n";
  }
};

class MyAcceptor: public EM::Acceptor {
  public:
  MyConnection *MakeConnection() { 
    cout << "Received new connection!\n";
    return new MyConnection();
  }  
};

void start () {
  EM::Acceptor *echo = new MyAcceptor();
  echo->Start("127.0.0.1", 2202);
}

int main() {
  cout << "Starting the Reactor..\n";
  EM::Run(start);
  cout << "Finished Successfully!\n";
  return 0
}

In order to get this to compile you'll need to create a static library for your application to link against.

The steps are as follows

  1. Open a terminal and cd into /ext inside of your unpacked gem directory
  2. Modify the extconf.rb to not add the -DBUILD_FOR_RUBY option for your particular build OS
  3. Apply this patch:
    --- ./ext/em.cpp	2008-06-17 14:40:07.000000000 -0700
    +++ ./ext/em.cpp	2008-06-28 20:18:11.000000000 -0700
    @@ -635,12 +635,14 @@
     _SelectDataSelect
     *****************/
     
    +#ifdef BUILD_FOR_RUBY
     static VALUE _SelectDataSelect (void *v)
     {
     	SelectData_t *sd = (SelectData_t*)v;
     	sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), NULL, &(sd->tv));
     	return Qnil;
     }
    +#endif
     
     /*********************
     SelectData_t::_Select
    @@ -648,6 +650,7 @@
     
     int SelectData_t::_Select()
     {
    +	#ifdef BUILD_FOR_RUBY
     	#ifdef HAVE_TBR
     	rb_thread_blocking_region (_SelectDataSelect, (void*)this, RB_UBF_DFL, 0);
     	return nSockets;
    @@ -656,6 +659,7 @@
     	#ifndef HAVE_TBR
     	return rb_thread_select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
     	#endif
    +	#endif
     }
     
    
  4. Run ARCHFLAGS="-arch i386" ruby extconf.rb && make (on OSX)
  5. Run ar cr libeventmachine.a *.o

This will give you a static library that you can link against.

One important thing to remember is that if your EventMachine files were compiled with any libraries (-lcrypto -lssl etc.) then your target application will need to pass those flags to the linker as well.

A sample project might look like the following

  • myserver
    • include
      • all header files
    • lib
      • libeventmachine.a
    • source
      • main.cpp

A typical compiler command (on OSX) for the previous directory setup may look like:

g++ -I. -I./include \
  -DHAVE_SYS_EVENT_H -DHAVE_SYS_QUEUE_H \
  -DHAVE_OPENSSL_SSL_H -DHAVE_OPENSSL_ERR_H  \
  -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -DOS_UNIX \
  -DHAVE_KQUEUE -DWITH_SSL \
  -fno-common -D_XOPEN_SOURCE=1  -fno-common -pipe -fno-common -c source/*.cpp

A typical linker command (on OSX) for the previous directory setup may look like:

g++ -o myserver main.o -L. -L./lib -L/usr/local/lib -leventmachine -lC -lcrypto -lssl  -lpthread -ldl -lobjc