[ja] apply patch

This commit is contained in:
Shin Kojima
2013-12-25 02:49:32 +09:00
parent 9976b34689
commit ef89ad1d3a

View File

@@ -226,6 +226,76 @@ Go言語ではnetパッケージの`DialTCP`関数によってTCP接続を一つ
タスク処理を関数`handleClinet`に分離することで、一歩進んで並列実行を実現できるようになります。見た目にはあまりかっこ良くありません。`go`キーワードを追加することでサーバの並列処理を実現しました。この例からgoroutineの強力さを見ることができます。
こう思う方もおられるかもしれません:このサーバはクライアントが実際にリクエストしたコンテンツを処理していない。もしもクライアントから異なるリクエストで異なる時刻形式を求められ、しかも長時間に渡る接続だった場合どうすればよいのか?と。その場合は以下をご覧ください:
package main
import (
"fmt"
"net"
"os"
"time"
"strconv"
)
func main() {
service := ":1200"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
for {
conn, err := listener.Accept()
if err != nil {
continue
}
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) // set 2 minutes timeout
request := make([]byte, 128) // set maxium request length to 128KB to prevent flood attack
for {
read_len, err := conn.Read(request)
if err != nil {
if err != io.EOF { // ignore EOF since client might send nothing for the moment
fmt.Println(err)
break
}
neterr, ok := err.(net.Error)
if ok && neterr.Timeout() {
fmt.Println(neterr)
break
}
}
if read_len == 0 {
continue
} else if string(request) == "timestamp" {
daytime := strconv.FormatInt(time.Now().Unix(), 10)
conn.Write([]byte(daytime))
} else {
daytime := time.Now().String()
conn.Write([]byte(daytime))
}
request = make([]byte, 128) // clear last read content
}
}
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}
上の例では`conn.Read()`を使用してクライアントが送信するリクエストを絶え間なく読み込んでいます。クライアントとの長時間接続を保持しなければならないため、一度のリクエストを読み終わった後も接続を切断することはできません。`conn.SetReadDeadline()`はタイムアウトを設定しているので、一定時間内にクライアントからリクエストが送られなければ、`conn`は自動的に接続を切断します。下のforループは接続が切断されることによって抜け出します。注意しなければならないのは、`request`は新規に作成される際にflood attackを防止するため最大の長さを指定しなければならないということです毎回リクエストが読み込まれ処理が完了する度にrequestを整理しなければなりません。なぜなら`conn.Read()`は新しく読み込んだ内容を元の内容の後にappendしてしまうかもしれないからです。
### TCP接続のコントロール
TCPには多くの接続コントロール関数があります。我々が普段よく使うものは以下のいくつかの関数です