gob反序列化不能在嵌套结构上很好地工作

时间:2020-05-16 14:41:13

标签: go gob

我正在编写rpc呼叫流程。当我使用tcp读写时,我发现了另一个嵌套的struct问题。我创建了一个包含traceId和struct请求对象或返回对象struct的请求和响应对象,但是当我在服务器上写回客户端的响应对象时,我无法在客户端gob反序列化上获得正确的答复。对象实体可以仅获取traceId。我想问这是什么原因。代码如下 在此处输入图片描述

// Server
for {
        // Read data from connection
        data, err := readData(conn)
        if err != nil {
            if err.Error() == "EOF" {
                return
            } else {
                log.Printf("Server readData error: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
                return
            }
        } else if len(data) == 0 {
            continue
        }

        // Decode the data from client request
        var req Request
        edcode, err := GetEdcode()
        if err != nil {
            log.Printf("Server encode error: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
            return
        }

        err = edcode.Decode(data, &req)
        if err != nil {
            log.Printf("Server decode error: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
            return
        }

        // Get the service from the registerd service map
        methodStr := strings.Split(req.MethodName, ".")
        if len(methodStr) != 2 {
            log.Printf("Server methodStr length invalid: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
            return
        }
        service := server.ServiceMap[methodStr[0]][methodStr[1]]

        // Construct the request args
        argv, err := req.MakeArgs(edcode, *service)

        // Construct reply data
        reply := reflect.New(service.ReplyType.Elem())

        // Call the method related
        function := service.Method.Func
        out := function.Call([]reflect.Value{reflect.New(server.ServerType.Elem()), argv, reply})
        if out[0].Interface() != nil {
            log.Printf("Server out result length invalid: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
            return
        }

        // Construct response data
        response := NewResponse(req.TraceId, reply.Elem().Interface())
        // We should register the matching type related to the GOB encoding to prevent the encoding error
        codeErr := response.RegisterGobRespType()
        if codeErr != nil {
            log.Printf("Server response.RegisterGobRespType eror : %v, remoteAddr:%v", codeErr.Error(), conn.RemoteAddr().String())
            return
        }

        // Encode the reply data to send to the client
        //replyData, err := edcode.Encode(reply.Elem().Interface())
        replyData, err := edcode.Encode(response)
        if err != nil {
            log.Printf("Server replayData encode error: %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
            return
        }   

        // Write data to connection
        _, err = writeData(conn, replyData)
        if err != nil {
            return
        }
    }
Client
// Receive and read the encoding response data from client
    replyData, err := readData(conn)
    if err != nil {
        log.Printf("Client writeData eror : %v, remoteAddr:%v", err.Error(), conn.RemoteAddr().String())
        return err
    }

    var response etnet.Response;
    // Decode data and assign it to reply variable
    //var response etnet.Response, response reply is always nil and I check the write value in server it is correct
    edcode.Decode(replyData, &response)

type Request struct {
    TraceId    string
    MethodName string
    Args       interface{}
}

type Response struct {
    TraceId string
    Reply   interface{}
}

func NewRequest(traceId string, methodName string, args interface{}) *Request {
    return &Request{
        TraceId:    traceId,
        MethodName: methodName,
        Args:       args,
    }
}

func NewResponse(traceId string, reply interface{}) *Response {
    return &Response{
        TraceId: traceId,
        Reply:   reply,
    }
}

// If encode in GOB we should register the type of Args to prevent the GOB encode error
func (request *Request) RegisterGobArgsType() error {
    edcodeStr := new(Config).GetEdcodeConf()
    switch edcodeStr {
    case "gob":
        args := reflect.New(reflect.TypeOf(request.Args))
        if args.Kind() == reflect.Ptr {
            args = args.Elem()
        }
        gob.Register(args.Interface())
        return nil
    case "json":
        return nil
    default:
        return errors.New("Unknown edcode protocol: " + edcodeStr)
    }
}

// If encode in GOB we should register the type of Args to prevent the GOB encode error
func (response *Response) RegisterGobRespType() error {
    edcodeStr := new(Config).GetEdcodeConf()
    switch edcodeStr {
    case "gob":
        reply := reflect.New(reflect.TypeOf(response.Reply))
        if reply.Kind() == reflect.Ptr {
            reply = reply.Elem()
        }
        gob.Register(reply.Interface())
        return nil
    case "json":
        return nil
    default:
        return errors.New("Unknown edcode protocol: " + edcodeStr)
    }
}

// Return the reflect.Value type of Args
func (request *Request) MakeArgs(edcode Edcode, service Service) (reflect.Value, error) {
    switch edcode.(type) {
    case GobEncode:
        return reflect.ValueOf(request.Args), nil
    case JsonEncode:
        reqArgs := request.Args.(map[string]interface{})
        argv := reflect.New(service.ArgType)
        err := MakeArgType(reqArgs, argv)
        if err != nil {
            log.Println(err.Error())
            return reflect.New(nil), err
        }
        if argv.Kind() == reflect.Ptr {
            argv = argv.Elem()
        }
        return argv, nil
    default:
        return reflect.ValueOf(request.Args), errors.New("Unknown edcode")
    }
}

0 个答案:

没有答案
相关问题