Aiming for Jarvis, Creating D.A.N.I.

Tutorial 23: Networking with TCP (or, Entering the Wild West)

If you've made it this far, congratulations. You've conquered the file system, wrestled with databases, and tamed the chaos of concurrency. But everything we've done so far has been local—a private conversation between your process and your hardware. Today, we open the window and let the wind in. We're talking about networking.

Networking is the true Wild West of programming. It’s where your perfectly clean code meets the "unreliable nature of the internet," where packets go missing, connections drop for no reason, and latency is the ghost in the machine.

A TCP client

In std/net, we keep it raw. A Connect call is your handshake, and Send/Recv are your voice. Don't expect magic; expect bytes.

module main

import "std/net"

fn main() -> int {
    // Open a connection to the void... or at least to a local port.
    conn, err := net.Connect("127.0.0.1", 12345)
    if err.message != "" {
        print("Failed to connect: {err.message}")
        return 1
    }

    // Send our greeting into the abyss
    sent := conn.Send("hello\n")
    if sent < 0 {
        print("Send failed")
        conn.Close()
        return 1
    }

    // Wait for the echo response
    response, rerr := conn.Recv(1024)
    if rerr.message != "" {
        print("Recv failed: {rerr.message}")
        conn.Close()
        return 1
    }

    print("Received: {response}")
    conn.Close()
    return 0
}

A TCP echo server

A server is just a loop that refuses to sleep, waiting for someone to knock. Accept is your gatekeeper.

fn main() -> int {
    listener, err := net.Listen("0.0.0.0", 12345)
    if err.message != "" {
        print("Listen failed: {err.message}")
        return 1
    }
    
    print("Server listening on 12345...")
    
    for {
        conn, aerr := net.Accept(listener)
        if aerr.message != "" {
            continue
        }
        
        // Handle the connection. In the real world, spawn this!
        data, rerr := conn.Recv(1024)
        if rerr.message == "" {
            conn.Send(data)
        }
        conn.Close()
    }
}

The HTTP shortcut

Need to fetch something quickly? Don't write a full protocol parser if you don't have to.

resp, err := net.HTTPGet("93.184.216.34", "/", 80)
if err.message == "" {
    print("Status: {resp.status}")
    print("Body: {resp.body}")
}

Just a word of caution: HTTPGet expects an IP address, not a hostname. DNS resolution is a rabbit hole for another day—and another tutorial.

Exercises

  1. The Handshake: Start the echo server in one terminal and the client in another. Watching those packets bounce back and forth is the simplest "it works" joy you'll find today.
  2. The User Interface: Modify your client to take input from the keyboard rather than sending "hello" every time.
  3. Concurrency Test: Take that server loop and spawn the connection handler. Try connecting twice at the same time—it’s the difference between a prototype and a real service.

Next

When you're ready to start talking to the world of sensors and IoT, we'll talk about MQTT and IoT.