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:

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:

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:


#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:

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:

IP Addresses: IPv4 and IPv6

An IP address uniquely identifies a device on a network. There are two versions:

IPv4

IPv6

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

  1. Your application asks the OS to resolve example.com
  2. The OS queries a DNS resolver (often your ISP’s or a public one like 8.8.8.8)
  3. The resolver checks its cache; if not found, it queries root servers, then TLD servers, then authoritative servers
  4. The resolver returns the IP address to your application
  5. Your application connects to the IP address

Record Types

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:

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:

HTTP/3 uses QUIC as its transport. QUIC is also used by other protocols like WebTransport.

WebSocket and Server-Sent Events

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:

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