Ch11.10: Socket Files
Overview
fast_io treats sockets as files. Once you have a socket file
object, you use the familiar print, println, and
scan APIs to send and receive data — no separate socket
library needed. This section covers the two main socket types and the free
functions that create them.
::fast_io::native_socket_file
::fast_io::native_socket_file is a thin wrapper around the
platform's raw socket handle:
-
POSIX (Linux, macOS, FreeBSD, …): a regular file
descriptor. On POSIX systems, sockets are file descriptors, so
this is just an
intwrapper. Important: On POSIX systems (including Cygwin and MSYS2),::fast_io::native_socket_fileis actually the same type as::fast_io::native_file. This is because POSIX treats sockets as file descriptors, so there is no distinction between a "socket file" and a "regular file" at the type level. -
Windows: a
SOCKEThandle wrapper. Windows sockets are not file descriptors, so this type carries the nativeSOCKETvalue instead. Only on native Windows (Win32) doesnative_socket_filediffer fromnative_file.
native_socket_file gives you unbuffered, raw access. For
typical TCP I/O you will want the buffered variant below.
::fast_io::iobuf_socket_file
::fast_io::iobuf_socket_file wraps a
native_socket_file in a basic_iobuf, adding
user-space buffering. This is the standard type for TCP
I/O.
Important: On non-Windows platforms (including POSIX, Cygwin, and MSYS2),
::fast_io::iobuf_socket_file is actually the same type as
::fast_io::iobuf_file. This mirrors the relationship between
native_socket_file and native_file — on POSIX systems,
sockets are just file descriptors, so there is no type-level distinction.
#include <fast_io.h>
int main() {
using namespace ::fast_io::iomnp;
// Initialize networking on Windows (no-op on POSIX)
::fast_io::net_service net_svc;
// Resolve hostname and connect
auto dns = ::fast_io::native_dns_file(u8"example.com");
::fast_io::iobuf_socket_file sock{::fast_io::tcp_connect(::fast_io::to_ip(dns, 80u16))};
// Send an HTTP GET request using the normal print API
print(sock,
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n");
// Read the response line by line using the normal scan API
::fast_io::string line;
while (scan<::fast_io::getline>(sock, line)) {
println(line);
}
}
Because the socket is buffered, many small print calls are
coalesced into fewer system calls, just like with
iobuf_file.
::fast_io::u8http_header_buffer
::fast_io::u8http_header_buffer is a specialised buffer for
parsing HTTP response (or request) headers. It is scannable
via scan_context_define, so you can feed it directly into the
normal scan pipeline:
header_length— total number of bytes consumed by the header.request()— the request method (for request headers).code()— the HTTP status code (for response headers).reason()— the reason phrase (e.g."OK","Not Found").
The default internal buffer size is 4096 bytes, which is enough for the vast majority of real-world HTTP headers.
#include <fast_io.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::net_service net_svc;
auto dns = ::fast_io::native_dns_file(u8"example.com");
::fast_io::iobuf_socket_file sock{::fast_io::tcp_connect(::fast_io::to_ip(dns, 80u16))};
print(sock,
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n");
// Parse the HTTP response header
::fast_io::u8http_header_buffer hdr;
scan(sock, hdr);
println("Status code: ", hdr.code());
println("Reason: ", hdr.reason());
println("Header len: ", hdr.header_length);
// The socket is now positioned at the start of the body.
// Continue reading the body with normal scan / print calls.
}
Free Functions for Sockets
The following free functions create and configure socket connections. They
return handles that can be used to construct
native_socket_file or iobuf_socket_file objects.
| Function | Description |
|---|---|
tcp_connect(host, port) |
Open a TCP connection to host:port. Returns a
native_socket_file.
|
tcp_listen(port) |
Create a TCP listening socket on the given port.
|
posix_bind(address) |
Bind a POSIX socket to the specified address. |
posix_listen(sockfd, backlog) |
Mark a bound POSIX socket as listening, with the given
backlog queue size.
|
posix_accept(sockfd) |
Accept an incoming connection on a listening POSIX socket. Returns a
new native_socket_file for the accepted connection.
|
TCP Server Example
Putting it all together, here is a minimal TCP server that listens on port 8080, accepts one connection, sends a greeting, and closes:
#include <fast_io.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::net_service net_svc;
// Listen on port 8080
auto listener = ::fast_io::tcp_listen(8080u16);
// Accept one incoming connection
::fast_io::native_socket_file conn{::fast_io::posix_accept(listener)};
// Wrap in a buffered socket for convenient I/O
::fast_io::iobuf_socket_file buf_conn{::fast_io::io::transmit(conn)};
// Send a greeting using the normal print API
println(buf_conn, "Hello from fast_io server!\n");
}
::fast_io::net_service
On Windows, the networking subsystem must be initialized before any socket operations
can be performed. This is done by calling WSAStartup() at program start
and WSACleanup() at program exit. ::fast_io::net_service is
a RAII wrapper that handles this automatically:
-
Windows (Win32): Constructs by calling
WSAStartup()and destructs by callingWSACleanup(). Create one instance at the beginning ofmain()to ensure the networking subsystem is initialized for the lifetime of your program. -
POSIX and other systems:
::fast_io::net_serviceis a no-op type with no constructor or destructor overhead. You can still create an instance for portability, but it does nothing.
#include <fast_io.h>
#include <fast_io_driver/tcp.h>
int main() {
using namespace ::fast_io::iomnp;
// Initialize networking on Windows (no-op on POSIX)
::fast_io::net_service net_svc;
// Now safe to use socket operations
::fast_io::iobuf_socket_file sock{::fast_io::tcp_connect("example.com", 80u16)};
print(sock,
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n");
::fast_io::string line;
while (scan<::fast_io::getline>(sock, line)) {
println(line);
}
}
Always create a ::fast_io::net_service object at the start of main()
if your program uses sockets. This ensures portability across platforms — on Windows it
initializes the networking subsystem, and on POSIX it is a harmless no-op.
DNS Resolution
When you need to connect to a host by name (rather than by IP address), you must first
resolve the hostname to an IP address. fast_io provides
::fast_io::native_dns_file for this purpose. It wraps the OS’s DNS
resolution facilities (getaddrinfo() on POSIX, GetAddrInfoW() on
Windows NT).
native_dns_file is iterable — it may resolve to multiple IP addresses
(both IPv4 and IPv6). You can iterate over all of them, or use the first result with
::fast_io::to_ip() to get an IP address with a port number, ready for
tcp_connect().
#include <fast_io.h>
int main() {
using namespace ::fast_io::iomnp;
::fast_io::net_service net_svc;
// Resolve hostname to IP addresses
::fast_io::native_dns_file dns(u8"example.com");
// Option 1: Use the first resolved address with a port
::fast_io::iobuf_socket_file sock{::fast_io::tcp_connect(::fast_io::to_ip(dns, 80u16))};
print(sock, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
// Option 2: Iterate over all resolved addresses
for (auto const& ent : dns) {
println("Resolved IP: ", ::fast_io::to_ip_address(ent));
}
}
The key functions are:
::fast_io::native_dns_file(hostname)— resolve a hostname to IP addresses::fast_io::to_ip(dns_entry, port)— convert a DNS entry to an IP address with port::fast_io::to_ip_address(dns_entry)— convert a DNS entry to just an IP address (no port)
Appendix: Network Basics
The OSI Model (Open Systems Interconnection)
The OSI model is a conceptual framework that standardizes the functions of a communication system into seven abstraction layers:
| Layer | Name | Description | Examples |
|---|---|---|---|
| 7 | Application | High-level protocols for user applications | HTTP, FTP, SMTP, DNS, SSH |
| 6 | Presentation | Data representation, encryption, compression | SSL/TLS, JPEG, MPEG |
| 5 | Session | Managing sessions between applications | NetBIOS, RPC |
| 4 | Transport | Reliable data transfer between hosts | TCP, UDP |
| 3 | Network | Routing and forwarding of packets | IP, ICMP, ARP |
| 2 | Data Link | Node-to-node data transfer | Ethernet, Wi-Fi, PPP |
| 1 | Physical | Physical transmission of raw bits | Ethernet cables, fiber optics, radio waves |
In practice, the TCP/IP model (a simpler 4-layer model) is more commonly used:
- Application Layer (combines OSI layers 5–7): HTTP, FTP, DNS, SMTP
- Transport Layer: TCP, UDP
- Internet Layer: IP, ICMP
- Network Access Layer (combines OSI layers 1–2): Ethernet, Wi-Fi
IP Addresses: IPv4 and IPv6
An IP address uniquely identifies a device on a network. There are two versions:
IPv4
- 32-bit address, written as four decimal numbers separated by dots
- Example:
192.168.1.1,8.8.8.8 - Address space: ~4.3 billion addresses (232)
- Running out of addresses due to Internet growth
- Special ranges:
127.0.0.1— localhost (loopback)10.0.0.0/8,172.16.0.0/12,192.168.0.0/16— private networks0.0.0.0— any address255.255.255.255— broadcast
IPv6
- 128-bit address, written as eight groups of four hexadecimal digits separated by colons
- Example:
2001:0db8:85a3:0000:0000:8a2e:0370:7334 - Can omit leading zeros and consecutive zero groups:
2001:db8:85a3::8a2e:370:7334 - Address space: ~3.4×1038 addresses (enough for every atom on Earth)
- Special addresses:
::1— localhost (loopback)::— any addressfe80::/10— link-local addresses
Common Ports
A port is a 16-bit number (0–65535) that identifies a specific service on a host. Well-known ports (0–1023) are assigned by IANA:
| Port | Protocol | Service |
|---|---|---|
| 20–21 | TCP | FTP (File Transfer Protocol) |
| 22 | TCP | SSH (Secure Shell) |
| 23 | TCP | Telnet (unencrypted, avoid) |
| 25 | TCP | SMTP (Simple Mail Transfer Protocol) |
| 53 | TCP/UDP | DNS (Domain Name System) |
| 67–68 | UDP | DHCP (Dynamic Host Configuration Protocol) |
| 80 | TCP | HTTP (Hypertext Transfer Protocol) |
| 110 | TCP | POP3 (Post Office Protocol v3) |
| 143 | TCP | IMAP (Internet Message Access Protocol) |
| 443 | TCP | HTTPS (HTTP Secure) |
| 465 | TCP | SMTPS (SMTP over SSL) |
| 587 | TCP | SMTP (submission, with STARTTLS) |
| 993 | TCP | IMAPS (IMAP over SSL) |
| 995 | TCP | POP3S (POP3 over SSL) |
| 3306 | TCP | MySQL |
| 3389 | TCP | RDP (Remote Desktop Protocol) |
| 5432 | TCP | PostgreSQL |
| 5900 | TCP | VNC (Virtual Network Computing) |
| 6379 | TCP | Redis |
| 8080 | TCP | HTTP alternate (often used for proxies) |
| 8443 | TCP | HTTPS alternate |
| 27017 | TCP | MongoDB |
Note: Ports 0–1023 are well-known ports (require root/admin to bind). Ports 1024–49151 are registered ports. Ports 49152–65535 are dynamic/ephemeral ports (used for client-side connections).
Appendix: DNS (Domain Name System)
DNS is the phonebook of the Internet. It translates human-readable domain names
(like example.com) into IP addresses (like 93.184.216.34) that
computers use to identify each other.
How DNS Works
- Your application asks the OS to resolve
example.com - The OS queries a DNS resolver (often your ISP’s or a public one like
8.8.8.8) - The resolver checks its cache; if not found, it queries root servers, then TLD servers, then authoritative servers
- The resolver returns the IP address to your application
- Your application connects to the IP address
Record Types
- A — IPv4 address (e.g.,
93.184.216.34) - AAAA — IPv6 address (e.g.,
2606:2800:220:1:248:1893:25c8:1946) - CNAME — Canonical name (alias for another domain)
- MX — Mail exchange (specifies mail servers)
- TXT — Text records (used for SPF, DKIM, etc.)
- NS — Name servers (delegates to other DNS servers)
- SOA — Start of authority (administrative info about the zone)
- PTR — Pointer (reverse DNS: IP to domain name)
- SRV — Service locator (for specific services)
DNS over HTTPS (DoH) and DNS over TLS (DoT)
Traditional DNS queries are sent in plaintext over UDP port 53, which can be intercepted or manipulated. Modern secure alternatives:
- DNS over HTTPS (DoH) — DNS queries sent over HTTPS (port 443), encrypted and authenticated
- DNS over TLS (DoT) — DNS queries sent over TLS (port 853), encrypted and authenticated
- DNSCrypt — Another encrypted DNS protocol
These protocols prevent eavesdropping, man-in-the-middle attacks, and DNS spoofing. They are increasingly supported by browsers and operating systems.
Appendix: Modern Network Protocols
HTTP/1.1 vs HTTP/2 vs HTTP/3
| Feature | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Year | 1997 | 2015 | 2022 |
| Transport | TCP | TCP | QUIC (over UDP) |
| Binary | Text | Binary | Binary |
| Multiplexing | No (head-of-line blocking) | Yes (streams over TCP) | Yes (streams over QUIC) |
| Header compression | No | HPACK | QPACK |
| Server push | No | Yes | Yes |
| Connection migration | No | No | Yes (switch networks seamlessly) |
| 0-RTT resume | No | No | Yes (faster connection setup) |
QUIC (Quick UDP Internet Connections)
QUIC is a transport layer protocol developed by Google and standardized by the IETF. It runs over UDP and provides:
- Lower latency — 0-RTT connection establishment (vs 3-way handshake in TCP)
- No head-of-line blocking — packet loss in one stream doesn’t block others
- Connection migration — can switch between Wi-Fi and cellular without dropping
- Built-in encryption — TLS 1.3 integrated at the transport layer
- Better congestion control — modern algorithms, easier to evolve than TCP (which is in the kernel)
HTTP/3 uses QUIC as its transport. QUIC is also used by other protocols like WebTransport.
WebSocket and Server-Sent Events
- WebSocket — Full-duplex communication over a single TCP connection. Starts with an HTTP upgrade request, then both sides can send data anytime. Used for chat, live updates, gaming.
- Server-Sent Events (SSE) — Server pushes updates to the client over HTTP. Simpler than WebSocket, but only server-to-client. Used for news feeds, notifications.
Appendix: Protocol Support in fast_io
Unlike Boost.Asio which focuses primarily on TCP and UDP, fast_io’s socket
API supports a wide range of protocols through the OS’s native socket interface:
- TCP — Reliable, connection-oriented streams (most common)
- UDP — Unreliable, connectionless datagrams (fast, low overhead)
- Unix domain sockets — Local inter-process communication (POSIX)
- Bluetooth — Bluetooth sockets (where supported by OS)
- Raw sockets — Direct access to IP/ICMP/etc. (requires root/admin)
- Other protocols — Any protocol supported by the OS’s socket API
The key difference: fast_io wraps the OS’s socket interface directly, so you
get access to everything the OS supports. You’re not limited to a hardcoded list of
protocols.
For TCP and UDP, fast_io provides convenience functions like
tcp_connect(), tcp_listen(), and DNS resolution. For other protocols,
you can construct socket files directly from the OS’s socket handles.
Key Takeaways
-
::fast_io::native_socket_filewraps the raw socket handle — a file descriptor on POSIX, aSOCKETon Windows. On non-Windows platforms (including Cygwin/MSYS2), it is the same type as::fast_io::native_file. -
::fast_io::iobuf_socket_fileadds user-space buffering and is the standard type for TCP I/O. On non-Windows platforms, it is the same type as::fast_io::iobuf_file. -
Use
::fast_io::native_dns_fileto resolve hostnames to IP addresses. Combine with::fast_io::to_ip(dns, port)andtcp_connect()to connect by hostname. -
::fast_io::u8http_header_bufferparses HTTP headers viascan. It exposesheader_length,request(),code(), andreason(). Default buffer size is 4096 bytes. -
Free functions:
tcp_connect(),tcp_listen(),posix_bind(),posix_listen(),posix_accept(). -
::fast_io::net_serviceis a RAII type that initializes the Windows networking subsystem (WSAStartup/WSACleanup). On POSIX systems it is a no-op. Always create one at the start ofmain()for portability. -
Sockets are files in
fast_io— the sameprint,scan, and customisation points you already know work for sockets too.