Master Go Socket and HTTP Programming: From Dial to Custom Requests

This article explains Go's socket programming workflow, the versatile net.Dial function for TCP, UDP, and ICMP connections, provides complete ICMP and TCP example programs, and then covers HTTP client usage with net/http, including basic methods, form posts, and custom request handling.

Raymond Ops
Raymond Ops
Raymond Ops
Master Go Socket and HTTP Programming: From Dial to Custom Requests

Socket Programming

Traditional socket programming follows five steps: create a socket with socket(), bind it with bind(), listen (or connect) with listen() / connect(), accept connections with accept(), and finally send or receive data using send() / receive(). Go's standard library abstracts this process so that any protocol can be used simply by calling net.Dial().

Dial() Function

The signature of Dial is: func Dial(net, addr string) (Conn, error) The net argument specifies the protocol name, and addr is the IP address or hostname optionally followed by a colon and port number. On success it returns a connection object; otherwise it returns an error.

Examples:

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

After establishing a connection, data can be sent with conn.Write() and received with conn.Read().

ICMP Example Program

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 // echo
    msg[1] = 0 // code 0
    // ... fill rest of ICMP header ...
    len := 8
    check := checkSum(msg[0:len])
    msg[2] = byte(check >> 8)
    msg[3] = byte(check & 0xff)
    _, err = conn.Write(msg[0:len])
    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 yields:

$ go build icmptest.go
$ ./icmptest www.baidu.com
Got response
Identifier matches
Sequence matches

TCP Example Program

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)
}
// checkError and readFully are the same as in the ICMP example

Execution example:

$ go build simplehttp.go
$ ./simplehttp qbox.me:80
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

HTTP is the most widely used Internet protocol. Go's standard library provides the net/http package, which implements both client and server functionality.

HTTP Client

The http.Client type offers several convenient methods:

func (c *Client) Get(url string) (r *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error)
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
func (c *Client) Head(url string) (r *Response, err error)
func (c *Client) Do(req *Request) (resp *Response, err error)

http.Get() fetches a URL with a single call:

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

http.Post() sends data with a POST request:

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

http.PostForm() submits a form using application/x-www-form-urlencoded encoding:

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

http.Head() retrieves only the response headers: resp, err := http.Head("http://example.com/") For more customized requests, create a http.Request and use Client.Do() to set custom headers such as User-Agent or cookies:

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)
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.

BackendGoNetwork programmingSocket
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

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.