Frontend Labs
⋯

35. curl: the easy/multi handle design and callback-driven I/O

What it is: the HTTP(S)/FTP/... client library behind nearly every language's HTTP bindings and an enormous share of embedded devices.

Concept mapping:

  • Opaque handles: CURL *curl = curl_easy_init(); returns a pointer to a struct whose definition is private to curl's .c files — callers only ever see a CURL * and interact through curl_easy_setopt/curl_easy_perform/curl_easy_cleanup. This is Section 13's static-for-privacy idea taken to the API level: the struct layout can change between curl versions without breaking binaries linked against it, because no caller code ever reads a field by name — this is Section 40's "designing a stable ABI," and it's why curl has kept API/ABI compatibility for over two decades.
  • Callback-driven I/O: CURLOPT_WRITEFUNCTION is exactly Section 11.2's function-pointer parameter — you hand curl a function pointer, and curl calls it with each chunk of the response body as it arrives, instead of you calling read() in a loop yourself:
size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
    FILE *out = userdata;
    return fwrite(ptr, size, nmemb, out);   // return value tells curl how many bytes you consumed
}

// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, out_file);
  • The multi interface (curl_multi_*) is Section 21/23's event-loop idea applied to outgoing connections: instead of blocking on one request at a time (curl_easy_perform), the multi API lets one thread drive hundreds of concurrent requests through a select()/poll()- style loop (curl_multi_fdset), the same non-blocking-I/O pattern as Redis's ae.c and Section 23.2's chat server, applied to a client instead of a server.

Generated from real-life-c-guide.md · 8 Oct 2026 16:36