第 1 章
[Day 1] Project initialization
Setup Go module
“Go module” is a dependency management for Go, it is a built-in feature after Go 1.13.
There’s a good tutorial from Go team: Tutorial: Create a Go module.
I initialized a go module by go mod init olivine in root of project, and it generated go.mod automatically.
Note: There’s a lot of project using
github.com/{username}/{repo_name}as go module name, it works well for most of projects and make others access GitHub repository directly and easy.
The main function
The main function is a special function which means “entrypoint of a program”, I created cmd/olivine/main.go.
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
We can run this code directly by go run ./cmd/olivine, you can see it shows “Hello World” on stdout.
$ go run ./cmd/olivine
Hello World
Hint: You can put
mainfuncion in any folder under go module withpackage maineven in project root. But I like to put binary source code undercmd/{binary_name}, it helps me manage projects by folder structures.
The Makefile
The make is a build tool for software development, it can use Makefile as a set of commands to help developers configure, compile, … and more!
All you need is create a Makefile in project root:
BIN_DIR := bin
CMD_DIR := cmd
build:
@echo "Building binaries..."
@mkdir -p $(BIN_DIR)
go build -o $(BIN_DIR)/olivine ./$(CMD_DIR)/olivine
clean:
@echo "Cleaning..."
@rm -rf $(BIN_DIR)
We defined two commands: build and clean.
build: Create folder for binaries if not exists, and compiles go binary to executable.clean: Cleanup binaries folder.
Now, use make build and it shows magic for you.
$ make build
$ ./bin/olivine # run the olivine binary
Hello World
Note: Don’t forget to add
bin/into.gitignore
A TCP Server
It’s time to build a TCP server!
There’s a good exaple from Go by Example: TCP Server.
package main
import (
"bufio"
"log/slog"
"net"
"strings"
)
func main() {
slog.Info("Listen :16879 for TCP connections...")
listener, err := net.Listen("tcp", ":16879")
if err != nil {
slog.Error("failed to listen tcp:", slog.Any("error", err))
return
}
defer listener.Close()
for {
connection, err := listener.Accept()
if err != nil {
slog.Error("failed to accept connection:", slog.Any("error", err))
continue
}
go handleConnection(connection)
}
}
func handleConnection(conn net.Conn) {
reader := bufio.NewReader(conn)
message, err := reader.ReadString('\n')
if err != nil {
slog.Error("failed to read from conn:", slog.Any("error", err))
return
}
ackmsg := strings.ToUpper(strings.ToUpper(message))
response := "ACK: " + ackmsg
if _, err := conn.Write([]byte(response)); err != nil {
slog.Error("failed to write to conn:", slog.Any("error", err))
return
}
}
Let’s test this TCP server with nc:
$ echo "hello" | nc 127.0.0.1 16879
> ACK: HELLO
$ echo "hello from netcat" | nc 127.0.0.1 16879
> ACK: HELLO FROM NETCAT
Congratulations! This is your new TCP Server written in Go.