Go Server #私藏項目實操分享#
Servers
用Go編寫網絡服務器是非常容易的。我們首先看一下如何創建一個TCP服務器:
package mainimport ( "encoding/gob" "fmt" "net")func server() { // listen on a port ln, err := net.Listen("tcp", ":9999") if err != nil { fmt.Println(err) return} for { // accept a connection c, err := ln.Accept() if err != nil { fmt.Println(err) continue } // handle the connection go handleServerConnection(c) }}func handleServerConnection(c net.Conn) { // receive the message var msg string err := gob.NewDecoder(c).Decode(&msg) if err != nil { fmt.Println(err) } else { fmt.Println("Received", msg) } c.Close()}func client() { // connect to the server c, err := net.Dial("tcp", "127.0.0.1:9999") if err != nil { fmt.Println(err) return } // send the message msg := "Hello World" fmt.Println("Sending", msg) err = gob.NewEncoder(c).Encode(msg) if err != nil { fmt.Println(err) } c.Close()}func main() { go server() go client() var input string fmt.Scanln(&input)}
這個例子使用了encoding/gob包,它可以很容易地對Go的數值進行編碼,以便其他G程序(或者在這種情況下是同一個Go程序)可以讀取它們。在encoding下面的包(如encoding/json)以及第三方包中都有其他的編碼方式。(例如,我們可以使用 labix.org/v2/mgo/bson來支持bson)。
HTTP
HTTP服務器的設置和使用更加容易。
package mainimport ( "io" "net/http")func hello(res http.ResponseWriter, req *http.Request) { res.Header().Set( "Content-Type", "text/html", ) io.WriteString( res, `
HandleFunc通過調用給定的函數來處理一個URL路由(/hello)。我們還可以通過使用FileServer來處理靜態文件
http.Handle( "/assets/", http.StripPrefix( "/assets/", http.FileServer(http.Dir("assets")), ),)
RPC
net/rpc(遠程過程調用)和 net/rpc/jsonrpc 軟件包提供了一種簡單的方法來公開方法,因此它們可以通過網絡被調用。 (而不是僅僅在運行它們的程序中)。
package mainimport ( "fmt" "net" "net/rpc")type Server struct{}func (this *Server) Negate(i int64, reply *int64) error { *reply = -i return nil}func server() { rpc.Register(new(Server)) ln, err := net.Listen("tcp", ":9999") if err != nil { fmt.Println(err) return } for { c, err := ln.Accept() if err != nil { continue } go rpc.ServeConn(c) }}func client() { c, err := rpc.Dial("tcp", "127.0.0.1:9999") if err != nil { fmt.Println(err) return } var result int64 err = c.Call("Server.Negate", int64(999), &result) if err != nil { fmt.Println(err) } else { fmt.Println("Server.Negate(999) =", result) }}func main() { go server() go client() var input string fmt.Scanln(&input)}
這個程序與TCP的例子相似,只是現在我們創建了一個對象來保存我們想要公開的所有方法,并且我們從 客戶端調用否定方法。更多細節請參見 net/rpc 的文檔。
剖析命令行參數
當我們在終端上調用一個命令時,有可能將該命令的參數傳遞給它。我們已經在go命令中看到了這一點
go run myfile.go
run 和 myfile.go 是參數。我們還可以將標志給一個命令。
go run -v myfile.go
標志包允許我們解析發送給我們程序的參數和標志。下面是一個生成0到6之間的數字的程序實例。我們可以通過發送一個標志(max=100)來改變最大值 程序
package mainimport ("fmt";"flag";"math/rand")func main() { // Define flags maxp := flag.Int("max", 6, "the max value") // Parse flag.Parse() // Generate a number between 0 and max fmt.Println(rand.Intn(*maxp))}
任何額外的非flag參數都可以通過 flag.Args() 來獲取。用 flag.Args() 檢索,它返回一個字符串數組。
同步原語
在Go中處理并發和同步的首選方式是通過goroutines和channel,正如第10章所討論的。然而,Go也提供了更多傳統的多線程例程,如sync 和 sync/atomic 包中提供了更為傳統的多線程例程.
Mutexes
互斥鎖(mutex)將一段代碼鎖定在一個單一的線程上。鎖定一段代碼,用于保護共享資源不受非原子操作的影響。用于保護共享資源免受非原子操作的影響。下面是 一個互斥鎖的例子:
package mainimport ( "fmt" "sync" "time")func main() { m := new(sync.Mutex) for i := 0; i < 10; i++ { go func(i int) { m.Lock() fmt.Println(i, "start") time.Sleep(time.Second) fmt.Println(i, "end") m.Unlock() }(i) } var input string fmt.Scanln(&input)}
當 mutex (m) 被鎖定時,任何其他試圖鎖定的行為都會被阻止,直到它被解鎖。在使用mutexes或sync/atomic包中提供的同步原語時,應該非常小心。
傳統的多線程編程是很困難的;很容易犯錯,而且這些錯誤很難發現,因為它們可能取決于非常具體的、相對罕見的、難以重現的一系列情況。Go最大的優勢之一是它所提供的并發功能比線程和鎖更容易理解和正確使用。
Go 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。