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("", 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 :40: +++ ./ext/em.cpp :18: @@ -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.
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
- include
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
