안녕하세요. 개발자 모도리입니다.
The Go Programming Language 라는 책으로 Go를 공부하고 있으며, 해당 책의 내용을 요약 정리해서 올리려고 합니다. 저는 번역본을 구매해서 공부하고 있습니다.
// Server1은 최소한의 "echo" 서버입니다.
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler) // 각 요청은 핸들러를 호출합니다.
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
// handler는 요청된 URL r의 Path 구성 요소를 반환합니다.
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
예제코드 [ch1/server1.go]
실행결과
$ go run ch1/server1.go
- 브라우저를 열어서 localhost:8000 에 접속하면 URL.Path = "/" 라는 메세지를 확인할 수 있습니다.
- localhost:8000/[path] : path 부분에 임의의 주소를 넣을 경우 해당 주소를 출력합니다.
/로 시작하는 URL에 핸들러 함수를 연결하고 8000번 포트로 들어오는 요청을 처리하는 서버를 시작합니다.fmt.Fprintf를 이용해 응답으로 돌려줍니다.// Server2는 최소한의 "echo" 및 카운터 서버입니다.
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
var mu sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
// 핸들러는 요청된 URL의 Path 구성 요소를 반환합니다.
func handler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
count++
mu.Unlock()
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
// counter는 지금까지 요청된 수를 반환합니다.
func counter(w http.ResponseWriter, r *http.Request) {
mu.Lock()
fmt.Fprintf(w, "Count %d\n", count)
mu.Unlock()
}
예제코드 [ch1/server2.go]
실행결과
$ go run ch1/server2.go
- 브라우저를 열어서 localhost:8000/count 에 접속하면 현재까지 요청했던 요청 횟수가 나옵니다.
// Server3은 디버깅하기 유용하게 요청의 헤더와 폼 데이터를 반환합니다.
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler) // 각 요청은 핸들러를 호출합니다.
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
// handler는 HTTP 요청을 반환합니다.
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
for k, v := range r.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
fmt.Fprintf(w, "Host = %q\n", r.Host)
fmt.Fprintf(w, "RemoteAddr = %q\n", r.RemoteAddr)
if err := r.ParseForm(); err != nil {
log.Print(err)
}
for k, v := range r.Form {
fmt.Fprintf(w, "Form[%q] = %q\n", k, v)
}
}
예제코드 [ch1/server3.go]
실행결과
$ go run ch1/server3.go
- 브라우저를 열어서 localhost:8000 에 접속하면 http.Request 정보를 출력합니다.
err := r.ParseForm()
if err != nil {
log.Print(err)
}
// Server4는 lissajous 애니메이션 GIF를 생성하여 http response로 반환합니다.
package main
import (
"image"
"image/color"
"image/gif"
"io"
"log"
"math"
"math/rand"
"net/http"
)
var palette = []color.Color{color.White, color.Black}
const (
whiteIndex = 0 // 팔레트의 첫 번째 색상
blackIndex = 1 // 팔레트의 다음 색상
)
func main() {
handler := func(w http.ResponseWriter, r *http.Request) {
lissajous(w)
}
http.HandleFunc("/", handler) // 각 요청은 핸들러를 호출합니다.
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
func lissajous(out io.Writer) {
const (
cycles = 5 // x 진동자의 회전수
res = 0.001 // 회전각
size = 100 // 이미지 캔버스 크기 [-size..+size]
nframes = 64 // 애니메이션 프레임 수
delay = 8 // 10ms 단위의 프레임 간 지연
)
freq := rand.Float64() * 3.0 // y 진동자의 상대적 진동수
anim := gif.GIF{LoopCount: nframes}
phase := 0.0 // 위상 차이
for i := 0; i < nframes; i++ {
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
img := image.NewPaletted(rect, palette)
for t := 0.0; t < cycles*2*math.Pi; t += res {
x := math.Sin(t)
y := math.Sin(t*freq + phase)
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
}
phase += 0.1
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim) // NOTE: 인코딩 오류 무시
}
예제코드 [ch1/server4.go]
실행결과
$ go run ch1/server4.go
- 브라우저를 열어서 localhost:8000 에 접속하면 lissajous 애니메이션이 출력됩니다.