mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 02:16:48 +08:00
update book code
This commit is contained in:
46
eBook/exercises/chapter_15/client1.go
Executable file
46
eBook/exercises/chapter_15/client1.go
Executable file
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"net"
|
||||
"bufio"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var conn net.Conn
|
||||
var error error
|
||||
var inputReader *bufio.Reader
|
||||
var input string
|
||||
var clientName string
|
||||
|
||||
// maak connectie met de server:
|
||||
conn, error = net.Dial("tcp", "localhost:50000")
|
||||
checkError(error)
|
||||
|
||||
inputReader = bufio.NewReader(os.Stdin)
|
||||
fmt.Println("First, what is your name?")
|
||||
clientName, _ = inputReader.ReadString('\n')
|
||||
// fmt.Printf("CLIENTNAME %s",clientName)
|
||||
trimmedClient := strings.Trim(clientName, "\r\n") // "\r\n" voor Windows, "\n" voor Linux
|
||||
|
||||
for {
|
||||
fmt.Println("What to send to the server? Type Q to quit. Type SH to shutdown server.")
|
||||
input, _ = inputReader.ReadString('\n')
|
||||
trimmedInput := strings.Trim(input, "\r\n")
|
||||
// fmt.Printf("input:--%s--",input)
|
||||
// fmt.Printf("trimmedInput:--%s--",trimmedInput)
|
||||
if trimmedInput == "Q" {
|
||||
return
|
||||
}
|
||||
_, error = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
|
||||
checkError(error)
|
||||
}
|
||||
}
|
||||
|
||||
func checkError(error error) {
|
||||
if error != nil {
|
||||
panic("Error: " + error.Error()) // terminate program
|
||||
}
|
||||
}
|
19
eBook/exercises/chapter_15/hello_server.go
Executable file
19
eBook/exercises/chapter_15/hello_server.go
Executable file
@@ -0,0 +1,19 @@
|
||||
// hello_server.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Hello struct{}
|
||||
|
||||
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "Hello!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
var h Hello
|
||||
http.ListenAndServe("localhost:4000",h)
|
||||
}
|
||||
// Output in browser-window with url http://localhost:4000: Hello!
|
31
eBook/exercises/chapter_15/http_fetch2.go
Executable file
31
eBook/exercises/chapter_15/http_fetch2.go
Executable file
@@ -0,0 +1,31 @@
|
||||
// httpfetch.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Print("Give the url from which to read: ")
|
||||
iread := bufio.NewReader(os.Stdin)
|
||||
url, _ := iread.ReadString('\n')
|
||||
url = strings.Trim(url," \n\r") // trimming space,etc.
|
||||
// fmt.Println("***", url,"***") // debugging
|
||||
res, err := http.Get(url)
|
||||
CheckError(err)
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
CheckError(err)
|
||||
fmt.Printf("Got: %q", string(data))
|
||||
}
|
||||
|
||||
func CheckError(err error) {
|
||||
if err != nil {
|
||||
log.Fatalf("Get: %v", err)
|
||||
}
|
||||
}
|
75
eBook/exercises/chapter_15/server1.go
Executable file
75
eBook/exercises/chapter_15/server1.go
Executable file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Map of the clients: contains: clientname - 1 (active) / 0 - (inactive)
|
||||
var mapUsers map[string]int
|
||||
|
||||
func main() {
|
||||
var listener net.Listener
|
||||
var error error
|
||||
var conn net.Conn
|
||||
mapUsers = make(map[string]int)
|
||||
|
||||
fmt.Println("Starting the server ...")
|
||||
|
||||
// create listener:
|
||||
listener, error = net.Listen("tcp", "localhost:50000")
|
||||
checkError(error)
|
||||
// listen and accept connections from clients:
|
||||
for {
|
||||
conn, error = listener.Accept()
|
||||
checkError(error)
|
||||
go doServerStuff(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func doServerStuff(conn net.Conn) {
|
||||
var buf []byte
|
||||
var error error
|
||||
|
||||
for {
|
||||
buf = make([]byte, 512)
|
||||
_, error = conn.Read(buf)
|
||||
checkError(error)
|
||||
input := string(buf)
|
||||
if strings.Contains(input, ": SH") {
|
||||
fmt.Println("Server shutting down.")
|
||||
os.Exit(0)
|
||||
}
|
||||
// op commando WHO: write out mapUsers
|
||||
if strings.Contains(input, ": WHO") {
|
||||
DisplayList()
|
||||
}
|
||||
// extract clientname:
|
||||
ix := strings.Index(input, "says")
|
||||
clName := input[0:ix-1]
|
||||
//fmt.Printf("The clientname is ---%s---\n", string(clName))
|
||||
// set clientname active in mapUsers:
|
||||
mapUsers[string(clName)] = 1
|
||||
fmt.Printf("Received data: --%v--", string(buf))
|
||||
}
|
||||
}
|
||||
|
||||
// advantage: code is cleaner,
|
||||
// disadvantage: the server process has to stop at any error:
|
||||
// a simple return continues in the function where we came from!
|
||||
func checkError(error error) {
|
||||
if error != nil {
|
||||
panic("Error: " + error.Error()) // terminate program
|
||||
}
|
||||
}
|
||||
|
||||
func DisplayList() {
|
||||
fmt.Println("--------------------------------------------")
|
||||
fmt.Println("This is the client list: 1=active, 0=inactive")
|
||||
for key, value := range mapUsers {
|
||||
fmt.Printf("User %s is %d\n", key, value)
|
||||
}
|
||||
fmt.Println("--------------------------------------------")
|
||||
}
|
104
eBook/exercises/chapter_15/statistics.go
Executable file
104
eBook/exercises/chapter_15/statistics.go
Executable file
@@ -0,0 +1,104 @@
|
||||
// statistics.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"strconv"
|
||||
"log"
|
||||
)
|
||||
|
||||
type statistics struct {
|
||||
numbers []float64
|
||||
mean float64
|
||||
median float64
|
||||
}
|
||||
|
||||
const form = `<html><body><form action="/" method="POST">
|
||||
<label for="numbers">Numbers (comma or space-separated):</label><br>
|
||||
<input type="text" name="numbers" size="30"><br />
|
||||
<input type="submit" value="Calculate">
|
||||
</form></html></body>`
|
||||
|
||||
const error = `<p class="error">%s</p>`
|
||||
|
||||
var pageTop = ""
|
||||
var pageBottom = ""
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", homePage)
|
||||
if err := http.ListenAndServe(":9001", nil); err != nil {
|
||||
log.Fatal("failed to start server", err)
|
||||
}
|
||||
}
|
||||
|
||||
func homePage(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.Header().Set("Content-Type", "text/html")
|
||||
err := request.ParseForm() // Must be called before writing response
|
||||
fmt.Fprint(writer, pageTop, form)
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, error, err)
|
||||
} else {
|
||||
if numbers, message, ok := processRequest(request); ok {
|
||||
stats := getStats(numbers)
|
||||
fmt.Fprint(writer, formatStats(stats))
|
||||
} else if message != "" {
|
||||
fmt.Fprintf(writer, error, message)
|
||||
}
|
||||
}
|
||||
fmt.Fprint(writer, pageBottom)
|
||||
}
|
||||
|
||||
func processRequest(request *http.Request) ([]float64, string, bool) {
|
||||
var numbers []float64
|
||||
if slice, found := request.Form["numbers"]; found && len(slice) > 0 {
|
||||
text := strings.Replace(slice[0], ",", " ", -1)
|
||||
for _, field := range strings.Fields(text) {
|
||||
if x, err := strconv.ParseFloat(field, 64); err != nil {
|
||||
return numbers, "'" + field + "' is invalid", false
|
||||
} else {
|
||||
numbers = append(numbers, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(numbers) == 0 {
|
||||
return numbers, "", false // no data first time form is shown
|
||||
}
|
||||
return numbers, "", true
|
||||
}
|
||||
|
||||
func getStats(numbers []float64) (stats statistics) {
|
||||
stats.numbers = numbers
|
||||
sort.Float64s(stats.numbers)
|
||||
stats.mean = sum(numbers) / float64(len(numbers))
|
||||
stats.median = median(numbers)
|
||||
return
|
||||
}
|
||||
|
||||
func sum(numbers []float64) (total float64) {
|
||||
for _, x := range numbers {
|
||||
total += x
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func median(numbers []float64) float64 {
|
||||
middle := len(numbers)/2
|
||||
result := numbers[middle]
|
||||
if len(numbers)%2 == 0 {
|
||||
result = (result + numbers[middle-1]) / 2
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func formatStats(stats statistics) string {
|
||||
return fmt.Sprintf(`<table border="1">
|
||||
<tr><th colspan="2">Results</th></tr>
|
||||
<tr><td>Numbers</td><td>%v</td></tr>
|
||||
<tr><td>Count</td><td>%d</td></tr>
|
||||
<tr><td>Mean</td><td>%f</td></tr>
|
||||
<tr><td>Median</td><td>%f</td></tr>
|
||||
</table>`, stats.numbers, len(stats.numbers), stats.mean, stats.median)
|
||||
}
|
29
eBook/exercises/chapter_15/template_validation_recover.go
Executable file
29
eBook/exercises/chapter_15/template_validation_recover.go
Executable file
@@ -0,0 +1,29 @@
|
||||
// template_validation_recover.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"text/template"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tOk := template.New("ok")
|
||||
tErr := template.New("error_template")
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Printf("run time panic: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
//a valid template, so no panic with Must:
|
||||
template.Must(tOk.Parse("/* and a comment */ some static text: {{ .Name }}"))
|
||||
fmt.Println("The first one parsed OK.")
|
||||
fmt.Println("The next one ought to fail.")
|
||||
template.Must(tErr.Parse(" some static text {{ .Name }"))
|
||||
}
|
||||
/* Output:
|
||||
The first one parsed OK.
|
||||
The next one ought to fail.
|
||||
2011/10/27 10:56:27 run time panic: template: error_template:1: unexpected "}" in command
|
||||
*/
|
33
eBook/exercises/chapter_15/twitter_status_json.go
Executable file
33
eBook/exercises/chapter_15/twitter_status_json.go
Executable file
@@ -0,0 +1,33 @@
|
||||
// twitter_status_json.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Status Status
|
||||
}
|
||||
|
||||
func main() {
|
||||
/* perform an HTTP request for the twitter status of user: Googland */
|
||||
res, _:= http.Get("http://twitter.com/users/Googland.json")
|
||||
/* initialize the structure of the JSON response */
|
||||
user := User{Status{""}}
|
||||
/* unmarshal the JSON into our structures */
|
||||
temp, _ := ioutil.ReadAll(res.Body)
|
||||
body := []byte(temp)
|
||||
json.Unmarshal(body, &user)
|
||||
fmt.Printf("status: %s", user.Status.Text)
|
||||
}
|
||||
/* Output:
|
||||
status: Robot cars invade California, on orders from Google:
|
||||
Google has been testing self-driving cars ... http://bit.ly/cbtpUN http://retwt.me/97p
|
||||
*/
|
24
eBook/exercises/chapter_15/webhello2.go
Executable file
24
eBook/exercises/chapter_15/webhello2.go
Executable file
@@ -0,0 +1,24 @@
|
||||
// webhello2.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func helloHandler(w http.ResponseWriter, r *http.Request) {
|
||||
remPartOfURL := r.URL.Path[len("/hello/"):] //get everything after the /hello/ part of the URL
|
||||
fmt.Fprintf(w, "Hello %s!", remPartOfURL)
|
||||
}
|
||||
|
||||
func shouthelloHandler(w http.ResponseWriter, r *http.Request) {
|
||||
remPartOfURL := r.URL.Path[len("/shouthello/"):] //get everything after the /shouthello/ part of the URL
|
||||
fmt.Fprintf(w, "Hello %s!", strings.ToUpper(remPartOfURL))
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/hello/", helloHandler)
|
||||
http.HandleFunc("/shouthello/", shouthelloHandler)
|
||||
http.ListenAndServe("localhost:9999", nil)
|
||||
}
|
Reference in New Issue
Block a user