FACE tutorial
Scenario
Server starts up and listen on port 9527, client will connect to server and send predefined RPC 'ping' with parameters: client version(int) and client name(char array), server will reply server version.
Steps
0. Install FACE
face2cpp
Face protocol 'compiler', require lex&yacc support. For Linux, with these 2 tools installed, go to /face2cpp directory:
somebody@localhost theface/face2cpp$ make
This will produce the utility 'face2cpp' Win32 version for face2cpp is not provided yet, but could be walk around easily with flex and bison windows version.
libface
Linux: Type 'make' in libface directory, be sure the libevent is installed into system.
somebody@localhost theface/face2cpp$ make
Windows: At 2008-01-16, the latest libevent port for WIN32 is version 1.1a, the Visual C++ library "libevent.lib" and "event.h" are both packed in the libface directory. Just use 'face.sln' to compile under Visual C++, this will produce face.lib for WIN32 environment.
1. Define the RPC
According to the scenario above, we wrote the following RPC description. Let's call it 'face protocol'. Resvered words are marked blue.
rpcset Sample{ c ping(int client_version, char client_name[16]) s pong(int server_version) }
Save it to as "sample.face"
2. Compile the protocol
Since we have the face 'compiler': face2cpp at step 0, now we are able to 'compile' the RPC definition into C++ source:
somebody@localhost theface/sample/protocol$ ../../face2cpp/face2cpp -f sample.face
This will produce C++ source file:
sample_srv.h sample_srv.cpp sample_cli.h sample_cli.cpp
Files above contain 2 class: SampleS and SampleC, those are RPC protocol described in C++, to be separately apply for server and client.
3. Make server
server.cpp is very simple:
Face<SampleS> f; // Declare what protocol to use int main(int argc, char **argv){ if(2 != argc){ usage(); exit(0); } f.listen_to(atoi(argv[1]), // port 10, // max_connection 1024 // buffer ); while(1) f.smile(); return 0; }
4. Make client
Client contains a little more:
int main(int argc, char **argv){ if(3 != argc){ usage(); exit(0); } Face<SampleC> f; // Here is the client logic f.set_connect_param(10, // max_connection 1024 // buffer ); Connection *c = f.connect_to(argv[1], atoi(argv[2])); char client_name[] = "NO 1 client"; f._logic->ping(c, 1, client_name, sizeof(client_name)); // send ping to server while(1) f.smile(); // smile(), aka heartbeat(), flushing network I/O buffers return 0; }
5. Fill in the logic
The files we generated above:
sample_srv.h sample_srv.cpp
Will be compiled with server.cpp. Header files contain all the dull work we don't wanna do like setup the socket and handle the buffer, so we leave them alone. In .cpp file, let's fill in the logic we want our program to behave.
server: what to do when ping() arrived from client, face2cpp already generated the function for us with the name: ping_on_receive(), All we need to do is reply pong() with server version, here we assume server version is 2008:
sample_srv.cpp: int SampleS::ping_on_receive(Connection *c, int client_version, char *client_name, int client_name_len){ f._logic->pong(c, 2008); return 0; };
All client need to do is display the server version when server replies client's ping() with pong():
sample_cli.cpp: int SampleS::pong_on_receive(Connection *c, int server_version){ cout<<"server version: "<<server_version<<endl; return 0; };
6. Build!
Here is server side Makefile, client is similar:
FACEPROTOCOL=../protocol/sample.face CXX=g++ FACECC=../../face2cpp/face2cpp FACESRC=sample_srv.cpp FACEHEADER=sample_srv.h SRC=$(wildcard *.cpp) OBJ=$(patsubst %.cpp,%.o,$(SRC)) LIBS=-ll -levent -L../../libface CXXFLAGS=-g -I../../libface FACEFLAGS=-s FACELIB=../../libface/libface.a PROG=sample_srv all: $(PROG) $(PROG): $(OBJ) $(CXX) $(OBJ) $(LIBS) $(FACELIB) $(CXXFLAGS) -o $(PROG) p: $(FACEPROTOCOL) $(FACECC) $(FACEFLAGS) -f $(FACEPROTOCOL) clean: rm -f *.o rm -f *~ rm -f $(FACESRC) $(FACEHEADER) rm -f $(PROG)
Steps 0-5 are used to demonstrate what FACE workflow is. Actual work is simple with this Makefile:
somebody@localhost theface/sample/server$ make p somebody@localhost theface/sample/server$ make
'make p' will generate the relevant C++ source file, and make will do the rest.
7. Test drive
Start server at port 9527:
somebody@localhost theface/sample/server$ ./simple_srv 9527
connect to server:
somebody@localhost theface/sample/client$ ./simple_cli 192.168.1.1 9527Have fun! Return to top