I'm building a SCPI electronics lab instrument for Linux. This post is an object oriented one again: testing if I can create a stream-like socket server in C++. TL;DR yes |
This blog post is a preparation for the SCPI programmable instrument I'm building for the Raspberry Pi and the PiFace Digital hat.
The SCPI parser will be in plain C: SCPI on a Linux Board - Part 1: Proof of Concept.
The instrument itself - a digital I/O device that's controlled by that SPI engine, will be written in C++. It's basically to feed my own interest .
The instrument will run as a service on the Pi, listening on a port for commands from the SCPI parser (that one will run a s a service listening to some port too).
In C++, input and output is typically done to and from streams. I'm going to test an example that provides a stream wrapper over TCP/IP sockets.
Sockets as Streams
The common way to create a socket listener in C is to use the network APIs.
#include <sys/socket.h> #include <netinet/in.h> // ... //Create socket socket_desc = socket(AF_INET, SOCK_STREAM, 0); if (socket_desc == -1) { printf("Could not create socket"); } puts("Socket created"); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(portno); //Bind if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) { //print the error message perror("bind failed. Error"); return 1; } puts("bind done"); while (1) { //Listen listen(socket_desc, 3); // ...
This works perfectly. The code above is part of the SCPI parser for my project.
But how to switch to a C++ io stream? The libraries have stream implementations for files and other OS resources, but not for TCP/IP traffic.
The boost.org C++ libraries do have a TCP/IP IO stream. I'm investigating their example here.
This is how a C++ TCP/IP socket server looks like:
try { boost::asio::io_service io_service; tcp::endpoint endpoint(tcp::v4(), 2223); tcp::acceptor acceptor(io_service, endpoint); for (;;) { tcp::iostream stream; acceptor.accept(*stream.rdbuf()); stream << make_daytime_string(); } } catch (std::exception& e) { std::cerr << e.what() << std::endl; }
(I changed the port from boost's example from 13 to 2223, because 13 is in a range that needs elevated rights (sudo) access)
The program above is just an example. It accepts a request. Upon connection, it sends the current time.
Because the loop creates a new stream each time, the original connection closes and you get a new one.
That's behaviour I may want to change or not. I don't know yet if I want to keep the communication between my SCPI parser and the instrument service open or not.
That's a decision I'll make once I integrate the two parts.
I'll create a side blog on how to get and build the BOOST libraries, and how to include them in your project.
Top Comments