Sockets with Adaptive Communication Environment (ACE) Framework

Adaptive Communication Environment, or ACE for short, is a C++ framework to develop portable, high-performance networked multithreaded applications. References below introduce in greater detail to the history of the framework.

ACE provides abstractions for sockets, demultiplexing loops, threads, synchronization primitives and can be used in high-performance, distributed real-time and embedded systems. ACE customers are Boeing and NASA, Facebook and Intel also use the framework – just a very short list of many ACE customers.
TAO is an implementation of CORBA Object Request Broker (ORB).

References:

There is little information about ACE on the Internet and the 3 books to learn the framework are over ten years old, despite the fact the framework is still actively maintained. The framework is large, over 2 million lines of code, and it takes an effort to learn how to use it. The solution that I provide here has several projects, each introducing to some of the concepts of the framework for network programming. I did not go into other capabilities the framework provides such as multithreading, shared memory management, service configuration, timers, etc. My interest was strictly in how to use it to abstract sockets. I hope it will make it easier for some of you to expand on my samples.

Trace samples show how to instrument your code to output configurable debug, trace, or error messages. Server samples show how to build server TCP endpoints to listen for Client requests. Any of the clients work with any of the servers. To launch a project, right-click on it and select Debug -> Start new instance.

The following image shows server and client talking to each other.

Udp projects demonstrate unicast, broadcast, and multicast support by ACE framework. Here’s a UDP dgram receiver example

void EchoDatagram() 
{ 
    ACE_INET_Addr  listener(27015, ACE_LOCALHOST); 
    ACE_INET_Addr  sender; 
    ACE_SOCK_DGRAM udp(listener); 

    char buffer[BUFSIZ]; 
    size_t size = sizeof(buffer); 

    cout << "waiting for a udp datagram." << endl; 

    ssize_t received = udp.recv(buffer, size, sender); 

    if (received > 0) 
    { 
        udp.send(buffer, size, sender); 
    } 

    udp.close(); 

    cout << "received: " << received << " bytes" << endl; 
} 

int ACE_TMAIN(int, ACE_TCHAR*[]) 
{ 
    EchoDatagram(); 
    return 0; 
}

A datagram can be sent to this receiver using the following sample:

int SendDatagram() 
{ 
    const char* message = "this is a message!\n"; 

    ACE_INET_Addr  sender    (27016, ACE_LOCALHOST); 
    ACE_INET_Addr  listener    (27015, ACE_LOCALHOST); 
    ACE_SOCK_DGRAM udp        (sender); 

    ssize_t sent = udp.send(message, ACE_OS_String::strlen(message) + 1, listener); 

    char buffer[BUFSIZ]; 
    size_t size = sizeof(buffer); 
    ssize_t received = udp.recv(buffer, size, listener); 

    udp.close(); 

    if (sent == -1) 
    { 
        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("send")), -1); 
    } 

    cout << "sent:     " << sent << " bytes" << endl; 
    cout << "received: " << received << " bytes" << endl; 

    return 0; 
} 

int ACE_TMAIN(int, ACE_TCHAR*[]) 
{ 
    int hr = SendDatagram(); 
    return hr; 
}
By convention, like many other frameworks, ACE utilizes debug and release libraries which can be loaded in code using #pragma comment or by listing them in the Linker properties dialog.
#if _DEBUG 
#pragma comment(lib, "aced") 
#else 
#pragma comment(lib, "ace") 
#endif

Following code example shows simple variants of trace macros:

int ACE_TMAIN(int, ACE_TCHAR*[]) 
{ 
    ACE_TRACE(ACE_TEXT("main")); 
    ACE_DEBUG((LM_INFO, ACE_TEXT("%IHi Mom\n"))); 

    foo(); 

    ACE_DEBUG((LM_INFO, ACE_TEXT("%IGoodnight\n"))); 

    return 0; 
} 

void foo() 
{ 
    ACE_TRACE(ACE_TEXT("foo")); 
    ACE_DEBUG((LM_INFO, ACE_TEXT("%IHowdy Partner\n"))); 
}

ACE server using reactor pattern can be written with just a few lines:

int ACE_TMAIN(int, ACE_TCHAR*[]) 
{ 
    ACE_INET_Addr        listenAddress(27015, ACE_LOCALHOST); 

    // Subscribe to events on a specific port 
    ClientAcceptor acceptor; 
    acceptor.reactor(ACE_Reactor::instance());            // Needed with ClientAcceptor 
    int hr = acceptor.open(listenAddress); 

    if (hr == -1) 
    { 
        return 1; 
    } 

    cout << "Listening for incoming connections..." << endl; 

    ACE_Reactor::instance()->run_reactor_event_loop(); 

    return 0; 
}
 All code is well commented explaining api’s in use.

Building ACE

I used 6.1.8 version of the framework, where stable versions are x.x.0 and work in progress has last number non-zero and could have bugs consequently. Download does not have binaries, you have to build them yourself. This is a big framework and the task takes time to accomplish. To simplify, I provided all required include, library and dll files in the ace.zip archive shown below.

If you build the library yourself you should extract the framework into ace_wrappers folder. If you use file that I provide in the ace.zip file you can place them anywhere, I copied them to c:\ace folder shown below.

The drill is the same as for any framework: dll’s from x64 folder should be copied to system32 or you can create an environment variable for them. You have to create an environment variable for the ace (or ace_wrappers) folder. You can do it using powershell with the following command:

[environment]::SetEnvironmentVariable("ACE_ROOT", "Machine", "c:\ace")
 

That’s how ace folder structure will look after all is done, where c:\ace\ace folder contains all includes.

Modify Visual Studio C++ directories and you are ready to run the code:

Summary

Hope this quick introduction to ACE framework will help you to get started. It is great to compare different styles and patterns when learning some concept or another and ACE is definitely a very well built set of libraries to enrich your programming and design skills.
All projects can be downloaded from here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: