patterncppMinor
Object-oriented Linux networking library
Viewed 0 times
networkinglibrarylinuxorientedobject
Problem
I needed to perform network communications in my Linux C++ project. I thought that it was a good idea to operate on a higher level of abstraction than raw system calls. Also I love OO design. So I'm implementing an object-oriented high-level Unix network open-source library (There are issues with tab-size if you watch source code on github, but the tabs are aligned well if watching in a text editor).
At the moment the library is partially implemented and is in a process of development. I've already tested some parts of it in real project and I find it's high level of abstraction extremely convenient.
The library checks all system calls for errors, so user shouldn't worry about checking every function's return status (thou exception system is still under construction). It allows easily convert socket addresses and strings in both directions. Socket classes provide convenient methods to get and set their properties, messages are sent and received as strings. TCP socket can recieve messages separated by terminator character or messages determined by required message size e.t.c.
I would like to know community's opinion if I made some design or implementation mistakes, if there could be done some improvements and if the library could be useful in some way to somebody. Any feedback is appreciated.
Here is a working example of a UDP echo-server implementation using my library.
```
#include
#include
#include
int main ( int argc , char** argv )
{
// Check program parameters to be provided
if ( argc != 3 )
{
std::cout ] [" << Unet::Ipv4Address(datagram.address).toString() << "] - " << datagram.message << std::endl;
}
}
// Catch and print all exceptions
catch ( Unet::Exception exception )
{
std::cout << "Unet exception: " << exception.getMessage() << std::endl;
}
catch ( std::exception exception )
{
std::cout << "Standard exception: " << exception.what(
At the moment the library is partially implemented and is in a process of development. I've already tested some parts of it in real project and I find it's high level of abstraction extremely convenient.
The library checks all system calls for errors, so user shouldn't worry about checking every function's return status (thou exception system is still under construction). It allows easily convert socket addresses and strings in both directions. Socket classes provide convenient methods to get and set their properties, messages are sent and received as strings. TCP socket can recieve messages separated by terminator character or messages determined by required message size e.t.c.
I would like to know community's opinion if I made some design or implementation mistakes, if there could be done some improvements and if the library could be useful in some way to somebody. Any feedback is appreciated.
Here is a working example of a UDP echo-server implementation using my library.
```
#include
#include
#include
int main ( int argc , char** argv )
{
// Check program parameters to be provided
if ( argc != 3 )
{
std::cout ] [" << Unet::Ipv4Address(datagram.address).toString() << "] - " << datagram.message << std::endl;
}
}
// Catch and print all exceptions
catch ( Unet::Exception exception )
{
std::cout << "Unet exception: " << exception.getMessage() << std::endl;
}
catch ( std::exception exception )
{
std::cout << "Standard exception: " << exception.what(
Solution
As Loki stated: don't re-invent the wheel. In the interest of learning and sharing, here are some ideas to consider:
Use an API already designed for parsing the command line. There must be dozens.
Since this is an object, I would hide the dependency as follows:
Since this is a networking object, I would prefer not to write the above statement at all. Rather, if the socket mustn't reuse the address, the API should provide a method to disable the behaviour.
A socket typically doesn't offer direct data reading and writing. The reason is that a data stream is a much more reusable concept. Were a developer to use your API, they would have to code functionality separately for reading from a socket vs. reading from a file. This restriction seems to limit the potential of software developed. Rather:
Now functionality can be written that reads data from any type of stream, making the source of the data independent (socket, file, database). If you absolutely must have the socket read/write datagrams, then use a terser method name:
This line:
Could be:
This simplifies the API for the developer. Otherwise all developers of the API will have to reference
Regarding the exception handling:
Having the API override
The
One more pet peeve:
Since the program doesn't actually continue forever, the loop should have a logical termination condition that tells the next person reading the source code when the program actually terminates. Some examples:
Regarding the bind method, consider the following pseudo-code:
Since the socket class already knows about
If developers are forced to hard-code a reference to IPv4 in their application, then they will have to do extra work to make the software use a different Internet Protocol version.
if ( argc != 3 )Use an API already designed for parsing the command line. There must be dozens.
socket.setOption(SO_REUSEADDR,1);Since this is an object, I would hide the dependency as follows:
socket.reuseAddress();Since this is a networking object, I would prefer not to write the above statement at all. Rather, if the socket mustn't reuse the address, the API should provide a method to disable the behaviour.
socket.hasUnreadData()A socket typically doesn't offer direct data reading and writing. The reason is that a data stream is a much more reusable concept. Were a developer to use your API, they would have to code functionality separately for reading from a socket vs. reading from a file. This restriction seems to limit the potential of software developed. Rather:
InputStream *dataIn = new SocketInputStream();
OutputStream *dataOut = new SocketOutputStream();
socket.setSource( dataIn );
socket.setDestination( dataOut );Now functionality can be written that reads data from any type of stream, making the source of the data independent (socket, file, database). If you absolutely must have the socket read/write datagrams, then use a terser method name:
socket.isReady()This line:
socket.bind(Unet::Ipv4Address(argv[1],argv[2]));Could be:
socket.bind(argv[1],argv[2]);This simplifies the API for the developer. Otherwise all developers of the API will have to reference
Ipv4Address. They shouldn't have to care. It's great to have the flexibility of putting in an Ipv6Address, but that can be handled automatically.Regarding the exception handling:
std::cout << "Unet exception: " << exception.getMessage() << std::endl;
std::cout << "Standard exception: " << exception.what() << std::endl;Having the API override
what(), eliminates the duplication:std::cout << "Exception: " << exception.what() << std::endl;The
what() method will differentiate the exception classes in its message.One more pet peeve:
while ( true )Since the program doesn't actually continue forever, the loop should have a logical termination condition that tells the next person reading the source code when the program actually terminates. Some examples:
while ( socket.isOpen() ) // Exit upon socket closure
while ( isRunning() ) // Exit upon user request
while ( !command.is( EXIT ) ) // Exit when the QUIT command is receivedRegarding the bind method, consider the following pseudo-code:
void Socket::bind( String host, String port ) {
Address *address = AddressFactory.newInstance( host );
bind( address, atoi( port ) );
}Since the socket class already knows about
Unet::Ipv4Address, adding a convenience method makes the class easier to use. Java gained popularity for a several reasons, including the simplicity of its networking API for trivial tasks. Using an AddressFactory, internally, will allow programs to work with either IPv4, IPv6, or any as-of-yet-invented protocol in the future. In C++, the application might have to be recompiled, but in Java, porting from IPv4 to IPv6 addresses has been mostly transparent.If developers are forced to hard-code a reference to IPv4 in their application, then they will have to do extra work to make the software use a different Internet Protocol version.
Code Snippets
if ( argc != 3 )socket.setOption(SO_REUSEADDR,1);socket.reuseAddress();socket.hasUnreadData()InputStream *dataIn = new SocketInputStream();
OutputStream *dataOut = new SocketOutputStream();
socket.setSource( dataIn );
socket.setDestination( dataOut );Context
StackExchange Code Review Q#30761, answer score: 2
Revisions (0)
No revisions yet.