go language implementation of the memcache protocol service method


This article illustrates an memcache protocol service implemented in the go language. Share with you for your reference. The details are as follows:

Click here to download the complete example code.

1. The Go language code is as follows:

package memcachep
import (
    "bufio"
    "fmt"
    "io"
    "strconv"
    "strings"
)
//mc Request to produce 1 a request object
type MCRequest struct {
    // Request command
    Opcode CommandCode
    //key
    Key string
    // Request content
    Value []byte
    // The request id
    Flags int
    // Request content length
    Length int
    // Expiration time
    Expires int64
}
//request to string
func (req *MCRequest) String() string {
    return fmt.Sprintf("{MCRequest opcode=%s, bodylen=%d, key='%s'}",
        req.Opcode, len(req.Value), req.Key)
}
// will socket Request content   Resolve to 1 a MCRequest object
func (req *MCRequest) Receive(r *bufio.Reader) error {
    line, _, err := r.ReadLine()
    if err != nil || len(line) == 0 {
        return io.EOF
    }
    params := strings.Fields(string(line))
    command := CommandCode(params[0])
    switch command {
    case SET, ADD, REPLACE:
        req.Opcode = command
        req.Key = params[1]
        req.Length, _ = strconv.Atoi(params[4])
        value := make([]byte, req.Length+2)
        io.ReadFull(r, value)
        req.Value = make([]byte, req.Length)
        copy(req.Value, value)
    case GET:
        req.Opcode = command
        req.Key = params[1]
        RunStats["cmd_get"].(*CounterStat).Increment(1)
    case STATS:
        req.Opcode = command
        req.Key = ""
    case DELETE:
        req.Opcode = command
        req.Key = params[1]
    }
    return err
}

2. Go language code:

package memcachep
import (
    "fmt"
    "io"
)
type MCResponse struct {
    // The command
    Opcoed CommandCode
    // Return status
    Status Status
    //key
    Key string
    // Returns the content
    Value []byte
    // Return to identify
    Flags int
    // error
    Fatal bool
}
// parsing response  And write the return result socket link
func (res *MCResponse) Transmit(w io.Writer) (err error) {
    switch res.Opcoed {
    case STATS:
        _, err = w.Write(res.Value)
    case GET:
        if res.Status == SUCCESS {
            rs := fmt.Sprintf("VALUE %s %d %d\r\n%s\r\nEND\r\n", res.Key, res.Flags, len(res.Value), res.Value)
            _, err = w.Write([]byte(rs))
        } else {
            _, err = w.Write([]byte(res.Status.ToString()))
        }
    case SET, REPLACE:
        _, err = w.Write([]byte(res.Status.ToString()))
    case DELETE:
        _, err = w.Write([]byte("DELETED\r\n"))
    }
    return
}

3. The Go language code is as follows:

package memcachep
import (
    "fmt"
)
type action func(req *MCRequest, res *MCResponse)
var actions = map[CommandCode]action{
    STATS: StatsAction,
}
// Waiting for distribution
func waitDispatch(rc chan chanReq) {
    for {
        input := <-rc
        input.response <- dispatch(input.request)
    }
}
// Distribute the request to the response action Operation function up
func dispatch(req *MCRequest) (res *MCResponse) {
    if h, ok := actions[req.Opcode]; ok {
        res = &MCResponse{}
        h(req, res)
    } else {
        return notFound(req)
    }
    return
}
// Unsupported command
func notFound(req *MCRequest) *MCResponse {
    var response MCResponse
    response.Status = UNKNOWN_COMMAND
    return &response
}
// to request Bind to the handler
func BindAction(opcode CommandCode, h action) {
    actions[opcode] = h
}
//stats
func StatsAction(req *MCRequest, res *MCResponse) {
    res.Fatal = false
    stats := ""
    for key, value := range RunStats {
        stats += fmt.Sprintf("STAT %s %s\r\n", key, value)
    }
    stats += "END\r\n"
    res.Value = []byte(stats)
}

I hope this article has helped you with your Go language programming.