Socket Stream#
Join provides C++ iostream wrappers for network sockets, enabling standard stream I/O operations.
Socket streams use std::streambuf internally and integrate seamlessly with C++ I/O facilities.
Socket streams are:
- standard‑compliant — work with all
std::iostreamfeatures - buffered — automatic buffering for efficiency
- timeout‑aware — configurable I/O timeouts
- type‑safe — support stream operators (
<<,>>)
Two stream types are available:
- BasicSocketStream — for TCP and Unix stream connections
- BasicTlsStream — for encrypted TLS/SSL connections
BasicSocketStream#
Standard iostream wrapper for stream sockets.
Creating a TCP stream#
#include <join/socketstream.hpp>
using namespace join;
Tcp::Stream stream;
Tcp::Endpoint server("example.com", 80);
stream.connect(server);Writing data#
// Using stream operators
stream << "GET / HTTP/1.1\r\n";
stream << "Host: example.com\r\n";
stream << "\r\n";
stream.flush();
// Using write methods
stream.write("Hello", 5);Reading data#
// Using stream operators
std::string line;
std::getline(stream, line);
// Reading formatted data
int value;
stream >> value;
// Reading raw data
char buffer[1024];
stream.read(buffer, sizeof(buffer));Stream state#
if (stream.good())
{
// Stream is ready for I/O
}
if (stream.fail())
{
// I/O operation failed
}
if (stream.eof())
{
// End of stream reached
}
// Clear error state
stream.clear();BasicTlsStream#
Encrypted iostream wrapper for TLS/SSL connections.
Creating a secure stream#
#include <join/socketstream.hpp>
using namespace join;
Tls::Stream stream;
// Configure TLS
stream.setVerify(true);
stream.setCaFile("/etc/ssl/certs/ca-bundle.crt");
Tls::Endpoint server("example.com", 443);
stream.connectEncrypted(server);The connectEncrypted() method:
- Establishes TCP connection
- Performs TLS handshake
- Waits for encryption to complete (using the stream timeout)
STARTTLS pattern#
Tls::Stream stream;
Tls::Endpoint server("mail.example.com", 587);
// Connect without encryption
stream.connect(server);
// Exchange plaintext
stream << "EHLO client.example.com\r\n";
stream.flush();
// ... wait for STARTTLS response ...
// Upgrade to TLS
stream.startEncryption();
if (stream.good())
{
// Now encrypted
}Certificate configuration#
// Set client certificate
stream.setCertificate("client.pem", "client-key.pem");
// Set trusted CA certificates
stream.setCaFile("/etc/ssl/certs/ca-bundle.crt");
stream.setCaPath("/etc/ssl/certs/");
// Enable peer verification
stream.setVerify(true);Cipher configuration#
// TLSv1.2 and below
stream.setCipher("ECDHE-RSA-AES256-GCM-SHA384");
// TLSv1.3
stream.setCipher_1_3("TLS_AES_256_GCM_SHA384");Timeout configuration#
Streams have a default timeout of 30 seconds for all I/O operations.
Setting timeout#
// Set 5 second timeout
stream.timeout(5000);
// Set infinite timeout (blocking)
stream.timeout(0);Getting current timeout#
int ms = stream.timeout();Timeouts apply to connection establishment, read and write operations, TLS handshake, and graceful disconnect.
Connection management#
Connecting#
Tcp::Stream stream;
Tcp::Endpoint server("192.168.1.100", 8080);
stream.connect(server);
if (stream.fail())
{
std::cerr << "Connection failed\n";
}Binding local endpoint#
Tcp::Stream stream;
stream.bind(Tcp::Endpoint("0.0.0.0", 5000));
stream.connect(Tcp::Endpoint("example.com", 80));Disconnecting#
// Graceful shutdown: flushes buffer, shuts down socket, waits for peer
stream.disconnect();
// Immediate close
stream.close();Connection state#
if (stream.opened()) { /* socket fd is open */ }
if (stream.connected()) { /* socket is connected */ }
if (stream.encrypted()) { /* TLS handshake completed (TLS streams only) */ }Buffering#
Streams use 4 KB buffers for both input and output.
Flushing output#
stream << "Hello\n";
stream.flush(); // ensure data is sent immediately
Automatic flushing occurs when the buffer is full, std::endl is used, flush() or sync() is called, or the stream is destroyed.
Note: On I/O errors,
underflow()andoverflow()close the underlying socket in addition to settingfailbit.
Stream examples#
HTTP client#
#include <join/socketstream.hpp>
#include <iostream>
using namespace join;
Tcp::Stream stream;
stream.connect(Tcp::Endpoint("example.com", 80));
stream << "GET / HTTP/1.1\r\n"
<< "Host: example.com\r\n"
<< "Connection: close\r\n"
<< "\r\n"
<< std::flush;
std::string line;
while (std::getline(stream, line))
{
std::cout << line << "\n";
}HTTPS client#
#include <join/socketstream.hpp>
#include <iostream>
using namespace join;
Tls::Stream stream;
stream.setVerify(true);
stream.setCaFile("/etc/ssl/certs/ca-bundle.crt");
stream.connectEncrypted(Tls::Endpoint("example.com", 443));
stream << "GET / HTTP/1.1\r\n"
<< "Host: example.com\r\n"
<< "Connection: close\r\n"
<< "\r\n"
<< std::flush;
std::string line;
while (std::getline(stream, line))
{
std::cout << line << "\n";
}Echo client#
#include <join/socketstream.hpp>
#include <iostream>
using namespace join;
Tcp::Stream stream;
stream.connect(Tcp::Endpoint("localhost", 9000));
stream.timeout(5000);
std::string message;
while (std::getline(std::cin, message))
{
stream << message << "\n" << std::flush;
std::string response;
std::getline(stream, response);
std::cout << "Echo: " << response << "\n";
}Unix domain stream#
#include <join/socketstream.hpp>
using namespace join;
UnixStream::Stream stream;
stream.connect(UnixStream::Endpoint("/tmp/server.sock"));
stream << "Hello from client\n" << std::flush;
std::string response;
std::getline(stream, response);Line‑based protocol#
using namespace join;
Tcp::Stream stream;
stream.connect(server);
stream << "COMMAND arg1 arg2\n" << std::flush;
std::string line;
std::getline(stream, line);
std::istringstream iss(line);
std::string status, message;
iss >> status;
std::getline(iss, message);Exception handling#
Streams can throw std::ios_base::failure when exceptions are enabled.
Enabling exceptions#
stream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
try
{
stream.connect(server);
stream << "Hello\n" << std::flush;
}
catch (const std::ios_base::failure& e)
{
std::cerr << "Stream error: " << e.what() << "\n";
}Without exceptions#
stream.connect(server);
if (stream.fail())
{
std::cerr << "Connection failed\n";
return;
}
stream << "Hello\n" << std::flush;
if (stream.fail())
{
std::cerr << "Write failed\n";
}Endpoint queries#
auto local = stream.localEndpoint();
auto remote = stream.remoteEndpoint();Accessing the underlying socket#
Tcp::Socket& sock = stream.socket();
sock.setOption(BasicSocket<Tcp>::Option::NoDelay, 1);
sock.setOption(BasicSocket<Tcp>::Option::KeepAlive, 1);Binary I/O#
struct Header { uint32_t length; uint16_t type; };
// Write
Header hdr = {1024, 42};
stream.write(reinterpret_cast<char*>(&hdr), sizeof(hdr));
stream.flush();
// Read
Header in;
stream.read(reinterpret_cast<char*>(&in), sizeof(in));
if (stream.gcount() == sizeof(in)) { /* success */ }Common patterns#
Request‑response protocol#
void sendRequest(Tcp::Stream& stream, const std::string& request)
{
stream << request << "\n" << std::flush;
}
std::string receiveResponse(Tcp::Stream& stream)
{
std::string response;
std::getline(stream, response);
return response;
}Read all available data#
std::string readAll(Tcp::Stream& stream)
{
std::ostringstream buf;
buf << stream.rdbuf();
return buf.str();
}Performance considerations#
- Default buffer size is 4 KB — reduces system calls automatically
- Flush explicitly when low latency matters
- Disable Nagle for latency-sensitive applications via
stream.socket().setOption(Option::NoDelay, 1) - Increase socket buffer sizes for high-throughput via
SndBuffer/RcvBufferoptions
Move semantics#
Streams are movable but not copyable:
Tcp::Stream s1;
Tcp::Stream s2 = std::move(s1);
std::vector<Tcp::Stream> v;
v.push_back(std::move(s2));Best practices#
- Use streams for text‑based protocols (HTTP, SMTP, etc.)
- Use raw sockets for binary protocols or when precise control is needed
- Always check stream state after I/O operations
- Set appropriate timeouts for your use case
- Enable exceptions for cleaner error handling in small programs
- Flush explicitly when immediate sending is required
- Use
disconnect()instead ofclose()for graceful shutdown - For TLS, always enable peer verification in production
Summary#
| Feature | BasicSocketStream | BasicTlsStream |
|---|---|---|
| Text I/O | ✅ | ✅ |
| Binary I/O | ✅ | ✅ |
| Stream operators | ✅ | ✅ |
| Buffering (4 KB) | ✅ | ✅ |
| Timeouts (default 30s) | ✅ | ✅ |
| TLS/SSL encryption | ❌ | ✅ |
| Certificate verification | ❌ | ✅ |
| STARTTLS | ❌ | ✅ |
| Graceful shutdown | ✅ | ✅ |
| Protocol | Stream Type | Use Case |
|---|---|---|
| UnixStream | BasicSocketStream | Local IPC |
| Tcp | BasicSocketStream | HTTP, custom text protocols |
| Tls | BasicTlsStream | Secure TCP |