mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
rpc: implement ServeRequest to synchronously serve a single request.
This is useful for applications that want to micromanage the rpc service. Moved part of ServeCodec into a new readRequest function. Renamed existing readRequest to readRequestHeader, and reordered its parameters to align with the new readRequest and service.call. R=golang-dev, r, rsc, sougou CC=golang-dev, msolomon https://golang.org/cl/4889043
This commit is contained in:
parent
de1f856d66
commit
9f677f91d1
2 changed files with 143 additions and 34 deletions
|
|
@ -394,7 +394,7 @@ func (server *Server) ServeConn(conn io.ReadWriteCloser) {
|
|||
func (server *Server) ServeCodec(codec ServerCodec) {
|
||||
sending := new(sync.Mutex)
|
||||
for {
|
||||
req, service, mtype, err := server.readRequest(codec)
|
||||
service, mtype, req, argv, replyv, err := server.readRequest(codec)
|
||||
if err != nil {
|
||||
if err != os.EOF {
|
||||
log.Println("rpc:", err)
|
||||
|
|
@ -402,9 +402,6 @@ func (server *Server) ServeCodec(codec ServerCodec) {
|
|||
if err == os.EOF || err == io.ErrUnexpectedEOF {
|
||||
break
|
||||
}
|
||||
// discard body
|
||||
codec.ReadRequestBody(nil)
|
||||
|
||||
// send a response if we actually managed to read a header.
|
||||
if req != nil {
|
||||
server.sendResponse(sending, req, invalidRequest, codec, err.String())
|
||||
|
|
@ -412,37 +409,31 @@ func (server *Server) ServeCodec(codec ServerCodec) {
|
|||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode the argument value.
|
||||
var argv reflect.Value
|
||||
argIsValue := false // if true, need to indirect before calling.
|
||||
if mtype.ArgType.Kind() == reflect.Ptr {
|
||||
argv = reflect.New(mtype.ArgType.Elem())
|
||||
} else {
|
||||
argv = reflect.New(mtype.ArgType)
|
||||
argIsValue = true
|
||||
}
|
||||
// argv guaranteed to be a pointer now.
|
||||
replyv := reflect.New(mtype.ReplyType.Elem())
|
||||
err = codec.ReadRequestBody(argv.Interface())
|
||||
if err != nil {
|
||||
if err == os.EOF || err == io.ErrUnexpectedEOF {
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
log.Println("rpc:", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
server.sendResponse(sending, req, replyv.Interface(), codec, err.String())
|
||||
continue
|
||||
}
|
||||
if argIsValue {
|
||||
argv = argv.Elem()
|
||||
}
|
||||
go service.call(server, sending, mtype, req, argv, replyv, codec)
|
||||
}
|
||||
codec.Close()
|
||||
}
|
||||
|
||||
// ServeRequest is like ServeCodec but synchronously serves a single request.
|
||||
// It does not close the codec upon completion.
|
||||
func (server *Server) ServeRequest(codec ServerCodec) os.Error {
|
||||
sending := new(sync.Mutex)
|
||||
service, mtype, req, argv, replyv, err := server.readRequest(codec)
|
||||
if err != nil {
|
||||
if err == os.EOF || err == io.ErrUnexpectedEOF {
|
||||
return err
|
||||
}
|
||||
// send a response if we actually managed to read a header.
|
||||
if req != nil {
|
||||
server.sendResponse(sending, req, invalidRequest, codec, err.String())
|
||||
server.freeRequest(req)
|
||||
}
|
||||
return err
|
||||
}
|
||||
service.call(server, sending, mtype, req, argv, replyv, codec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (server *Server) getRequest() *Request {
|
||||
server.reqLock.Lock()
|
||||
req := server.freeReq
|
||||
|
|
@ -483,7 +474,38 @@ func (server *Server) freeResponse(resp *Response) {
|
|||
server.respLock.Unlock()
|
||||
}
|
||||
|
||||
func (server *Server) readRequest(codec ServerCodec) (req *Request, service *service, mtype *methodType, err os.Error) {
|
||||
func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, err os.Error) {
|
||||
service, mtype, req, err = server.readRequestHeader(codec)
|
||||
if err != nil {
|
||||
if err == os.EOF || err == io.ErrUnexpectedEOF {
|
||||
return
|
||||
}
|
||||
// discard body
|
||||
codec.ReadRequestBody(nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Decode the argument value.
|
||||
argIsValue := false // if true, need to indirect before calling.
|
||||
if mtype.ArgType.Kind() == reflect.Ptr {
|
||||
argv = reflect.New(mtype.ArgType.Elem())
|
||||
} else {
|
||||
argv = reflect.New(mtype.ArgType)
|
||||
argIsValue = true
|
||||
}
|
||||
// argv guaranteed to be a pointer now.
|
||||
if err = codec.ReadRequestBody(argv.Interface()); err != nil {
|
||||
return
|
||||
}
|
||||
if argIsValue {
|
||||
argv = argv.Elem()
|
||||
}
|
||||
|
||||
replyv = reflect.New(mtype.ReplyType.Elem())
|
||||
return
|
||||
}
|
||||
|
||||
func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, err os.Error) {
|
||||
// Grab the request header.
|
||||
req = server.getRequest()
|
||||
err = codec.ReadRequestHeader(req)
|
||||
|
|
@ -568,6 +590,12 @@ func ServeCodec(codec ServerCodec) {
|
|||
DefaultServer.ServeCodec(codec)
|
||||
}
|
||||
|
||||
// ServeRequest is like ServeCodec but synchronously serves a single request.
|
||||
// It does not close the codec upon completion.
|
||||
func ServeRequest(codec ServerCodec) os.Error {
|
||||
return DefaultServer.ServeRequest(codec)
|
||||
}
|
||||
|
||||
// Accept accepts connections on the listener and serves requests
|
||||
// to DefaultServer for each incoming connection.
|
||||
// Accept blocks; the caller typically invokes it in a go statement.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue