Master Go Socket and HTTP Programming: Dial, ICMP, and Custom Requests

Learn how to use Go's net package for low‑level socket programming—including TCP, UDP, and ICMP connections with the Dial function—and build HTTP clients with net/http, covering basic requests, POST forms, custom headers, and practical code examples.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master Go Socket and HTTP Programming: Dial, ICMP, and Custom Requests

Socket Programming with Go

The traditional socket workflow (create, bind, listen/connect, accept, send/receive) is abstracted in Go's standard library. By calling net.Dial you can open a connection for any supported protocol without manually handling the low‑level steps.

Dial Function Signature

func Dial(net, addr string) (Conn, error)
net

specifies the protocol name (e.g., "tcp", "udp", "ip4:icmp"), and addr is the host and optional port ("host:port"). If the connection succeeds, a Conn object is returned; otherwise an error is returned.

Typical Dial Usages

TCP: conn, err := net.Dial("tcp", "192.168.0.10:2100") UDP: conn, err := net.Dial("udp", "192.168.0.12:975") ICMP (IPv4): conn, err := net.Dial("ip4:icmp", "www.baidu.com") ICMP (raw): conn, err := net.Dial("ip4:1", "10.0.0.3") Supported network strings include "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", and "ip6".

Sending and Receiving Data

After establishing a connection, use conn.Write() to send bytes and conn.Read() to receive them.

ICMP Example Program

The following Go program sends an ICMP echo request to a host and validates the identifier and sequence fields in the reply.

package main
import (
    "net"
    "os"
    "bytes"
    "fmt"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Usage:", os.Args[0], "host")
        os.Exit(1)
    }
    service := os.Args[1]
    conn, err := net.Dial("ip4:icmp", service)
    checkError(err)

    var msg [512]byte
    msg[0] = 8   // Type: Echo
    msg[1] = 0   // Code
    // checksum placeholder
    msg[4] = 0   // Identifier[0]
    msg[5] = 13  // Identifier[1]
    msg[6] = 0   // Sequence[0]
    msg[7] = 37  // Sequence[1]
    length := 8
    check := checkSum(msg[0:length])
    msg[2] = byte(check >> 8)
    msg[3] = byte(check & 0xff)

    _, err = conn.Write(msg[0:length])
    checkError(err)
    _, err = conn.Read(msg[0:])
    checkError(err)
    fmt.Println("Got response")
    if msg[5] == 13 {
        fmt.Println("Identifier matches")
    }
    if msg[7] == 37 {
        fmt.Println("Sequence matches")
    }
    os.Exit(0)
}

func checkSum(msg []byte) uint16 {
    sum := 0
    for n := 1; n < len(msg)-1; n += 2 {
        sum += int(msg[n])*256 + int(msg[n+1])
    }
    sum = (sum >> 16) + (sum & 0xffff)
    sum += sum >> 16
    return ^uint16(sum)
}

func checkError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}

func readFully(conn net.Conn) ([]byte, error) {
    defer conn.Close()
    result := bytes.NewBuffer(nil)
    var buf [512]byte
    for {
        n, err := conn.Read(buf[0:])
        result.Write(buf[0:n])
        if err != nil {
            if err == io.EOF {
                break
            }
            return nil, err
        }
    }
    return result.Bytes(), nil
}

Running the program (e.g., ./icmptest www.baidu.com) prints:

Got response
Identifier matches
Sequence matches

TCP Example Program (Simple HTTP HEAD)

This example opens a TCP connection to a host, sends an HTTP HEAD request, and prints the response headers.

package main
import (
    "net"
    "os"
    "bytes"
    "fmt"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Fprintf(os.Stderr, "Usage: %s host:port
", os.Args[0])
        os.Exit(1)
    }
    service := os.Args[1]
    conn, err := net.Dial("tcp", service)
    checkError(err)
    _, err = conn.Write([]byte("HEAD / HTTP/1.0

"))
    checkError(err)
    result, err := readFully(conn)
    checkError(err)
    fmt.Println(string(result))
    os.Exit(0)
}

func checkError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}

func readFully(conn net.Conn) ([]byte, error) {
    defer conn.Close()
    result := bytes.NewBuffer(nil)
    var buf [512]byte
    for {
        n, err := conn.Read(buf[0:])
        result.Write(buf[0:n])
        if err != nil {
            if err == io.EOF {
                break
            }
            return nil, err
        }
    }
    return result.Bytes(), nil
}

Executing ./simplehttp qbox.me:80 yields a typical HTTP response header, e.g.,

HTTP/1.1 301 Moved Permanently
Server: nginx/1.0.14
Date: Mon, 21 May 2012 03:15:08 GMT
Content-Type: text/html
Content-Length: 184
Connection: close
Location: https://qbox.me/

HTTP Programming with Go's net/http Package

The net/http package provides both client and server implementations. The following sections show how to perform common HTTP operations.

Basic HTTP Client Methods

http.Get(url)

– simple GET request. http.Post(url, bodyType, body) – POST with raw body. http.PostForm(url, data) – POST with form‑encoded data. http.Head(url) – retrieve only response headers. client.Do(req) – full control over request, useful for custom headers or cookies.

GET Example

resp, err := http.Get("http://example.com/")
if err != nil {
    // handle error
    return
}
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)

POST Example (Uploading an Image)

resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf)
if err != nil {
    // handle error
    return
}
if resp.StatusCode != http.StatusOK {
    // handle non‑OK response
    return
}

POST Form Example

resp, err := http.PostForm("http://example.com/posts", url.Values{
    "title":   {"article title"},
    "content": {"article body"},
})
if err != nil {
    // handle error
    return
}

HEAD Request Example

resp, err := http.Head("http://example.com/")
// resp.Header now contains the header fields

Custom Request with Do

When more control is needed (e.g., setting a custom User-Agent or adding cookies), construct a http.Request and use an http.Client to execute it.

req, err := http.NewRequest("GET", "http://example.com", nil)
req.Header.Add("User-Agent", "Gobook Custom User-Agent")
client := &http.Client{}
resp, err := client.Do(req)
// process resp

These examples demonstrate how Go simplifies both low‑level socket interactions and high‑level HTTP client operations, allowing developers to build networked applications efficiently.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentGonetworkHTTPsocket programming
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.