go语言五——http模块实现个状态计数器

实现一个简易的“状态机”

server # go run server.go
2013/06/06 14:10:11 counterB timedout
 //超时10秒总和未达到10

client # go run client.go counterA 1
Continue
client # go run client.go counterA 3
Continue
client # go run client.go counterA 3
Continue
client # go run client.go counterA 4 //counterA十秒内数字和>10
Done

client # go run client.go counterB 4 //超时10秒总和未达到10
Continue

用go自带的库实现http服务器端server.go:

package main

import (
	"fmt"
	"net/http"
	"log"
	"os"
//	"os/signal"
	"g10086"
	"bufio"
	"io"
	"strings"
	"time"
	"encoding/json"
	"strconv"
//	"syscall"
)

//g10086 location 记录的配置文件
const g10086_save = "g10086.status"

//查看当前g10086的全局状态信息
func rootHandler (w http.ResponseWriter, r * http.Request) {
	fmt.Fprintf(w, "g_status: %d\n", len(g10086.G_status))

	for key,val := range g10086.G_status {
		fmt.Fprintf(w, "%s : %s\n", key, val)
	}
}

//将全局状态信息表存储到文件中
func saveHandler (w http.ResponseWriter, r * http.Request) {
	save_status()
	io.WriteString(w, "Save OK!")
}

//从文件加载信息
func load_status () {
	g10086.G_status = make(map[string] string)

	f, err := os.OpenFile(g10086_save, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	r := bufio.NewReader(f)  
        line, _, err := r.ReadLine()  
        for err == nil {  
		if info := strings.Split(string(line)," "); len(info) > 1 {
			g10086.G_status[info[0]] = info[1]
		}
                line, _, err = r.ReadLine()  
        }  
}

func save_status () {
	f, err := os.OpenFile(g10086_save, os.O_CREATE|os.O_RDWR, 0666) 
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	b := bufio.NewWriter(f) 
	for key,value := range g10086.G_status {
		line := key + " " + value + "\n"
		if n, err := b.WriteString(line); err != nil || n != len(line) {  
                	log.Fatal(err)  
        	}
	}
	if err = b.Flush(); err != nil {  
                log.Fatal(err)  
        } 
}

//查看全局状态信息是否有超时的信息,如果有,删除并记录日志
func check_timeout() {
	cur := time.Now().Unix()
	
	for key,value := range g10086.G_status {
		var cur_down g10086.Dstate //不能放在for循环之前!
		dec := json.NewDecoder(strings.NewReader(value))
		if err := dec.Decode(&cur_down); err != nil {
			return
		}
		for k,_ := range cur_down.Info {
			t, err := strconv.Atoi(k)
			if err != nil {
				return
			}
			if t < int(cur - 10) {
				delete(g10086.G_status, key)
				log.Println(key + " timedout")
				break
			}
		}
	}
}

//定时器,每1秒钟运行一次,检测超时
func timer () {
	for {
		timer := time.NewTicker(1 * time.Second)
		for {
			select {
			case <- timer.C:
				check_timeout()
			}
		}
	}
}

//配置服务器,监听端口和location
func main () {

	load_status () 

	go timer()
	defer save_status()

	http.HandleFunc("/",rootHandler)
	http.HandleFunc("/g10086",g10086.G10086Handler)
	http.HandleFunc("/save",saveHandler)

	log.SetOutput(os.Stdout)

	err := http.ListenAndServe("127.0.0.1:8088", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

g10086/g10086.go 模块代码如下

package g10086

import (
	"io"
	"net/http"
	"strings"
	"strconv"
	"encoding/json"
	"time"
)

//全局计数器信息
var G_status map[string] string

//
type Dstate struct {
	id string
	status string
	Info map[string] string
}

//更新计数状态,如果计数器A的数字总和超过10,则输出完毕,删除此计数器
func updateStatus (key string, down Dstate) int {

	total := 0

	for _,v := range down.Info {
		n, err := strconv.Atoi(v)
		if err != nil {
			return -1
		}
		total += n
		if total > 10 {
			down.status = "Done"
			break
		}
	}

	if (down.status == "Done") {
		if _, ok := G_status[key]; ok {
			delete(G_status,key)
		}

		return 1
	} else {
		downinfo, err := json.Marshal(down)
		if err == nil {
			G_status[key] = string(downinfo)
		}
		return 0
	}
}

func G10086Handler (w http.ResponseWriter, r *http.Request) {

	key, val := r.PostFormValue("key"), r.PostFormValue("value")
	if key == "" || val == "" {
		io.WriteString(w,"no para")
		return
	}

	//查询之前有无对应key的计数器,如果有,则添加记录,如果没有,新建记录
	var cur_down Dstate
	if v, ok := G_status[key]; ok {
		dec := json.NewDecoder(strings.NewReader(v))
		if err := dec.Decode(&cur_down); err != nil {  
            		return
		}
		cur_down.Info[strconv.Itoa(int(time.Now().Unix()))] = val
	} else {
		new_status := map[string] string{strconv.Itoa(int(time.Now().Unix())):val}
		cur_down = Dstate{id:key, status:"Start", Info:new_status}
	}
	res := updateStatus(key, cur_down)

	switch res {
	case 1:
		io.WriteString(w, "Done" + key)
	case 0:
		io.WriteString(w, "Continue " + key)
	default:
		io.WriteString(w, "Unknown")
	}
}

client端代码如下:

package main

import (
	"net/http"
	"net/url"
	"log"
	"os"
)

func main () {

	if len(os.Args) < 3 {
		log.Fatal("para error")
	}
	key, val := os.Args[1], os.Args[2]

	resp, err := http.PostForm("http://127.0.0.1:8088/g10086",
			url.Values{"key": {key}, "value": {val}})
	if err != nil {
		log.Fatal("Post error : ", err)
	}

	if resp.StatusCode == 200 {
		resp.Write(os.Stdout)
	}
}


//使用示例
//go run client.go countA 3
//go run client.go countB 4

静态文件需要添加如下代码,创建template目录,将静态资源放在目录中

http.Handle("/template/", http.StripPrefix("/template/", http.FileServer(http.Dir("./template"))))

 同样的静态资源小文件放在nginx和go的性能测试如下:Request Per Second(nginx为7652)(go为5321)

定时器使用如下:

import "time"

func timer () {
        for {
                timer := time.NewTicker(5 * time.Second)
                for {
                        select {
                        case <- timer.C:
                                fmt.Print("timer called\n")
                        }
                }
        }
}

 JSON操作

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    const jsonStream = `
        {"Name": "Ed", "Text": "Knock knock."}
        {"Name": "Sam", "Text": "Who's there?"}
        {"Name": "Ed", "Text": "Go fmt."}
        {"Name": "Sam", "Text": "Go fmt who?"}
        {"Name": "Ed", "Text": "Go fmt yourself!"}
    `
    type Message struct {
        Name, Text string
    }
    //json decode
    dec := json.NewDecoder(strings.NewReader(jsonStream))
    var m Message
    for {
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s\n", m.Name, m.Text)
    }
    //json encode
    dataStream, err := json.Marshal(m)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Print(string(dataStream))
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值