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