EventMachine and CPP

akzhan edited this page Jun 27, 2011 · 3 revisions

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

  • Open a terminal and cd into /ext inside of your unpacked gem directory
  • Modify the extconf.rb to not add the -DBUILD_FOR_RUBY option for your particular build OS
  • 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
 }
  • Run ARCHFLAGS=“-arch i386” ruby extconf.rb && make (on OSX)
  • Run ar cr libeventmachine.a *.o

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

There is an example rake file available to build CPP programs with.

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