golang rpc的两种使用和测试是否可用
go的rpc可以使用http的方式,也可以使用tcp的,这里两种一起使用,如果服务挂了,我们可以通过http来测试服务是否正常。
server.go
package main
import (
"net/rpc"
"net/http"
"log"
"net"
// "time"
)
type Args struct {
A, B int
}
type Arith int
func (t *Arith) Multiply(args *Args, reply *([]string)) error {
*reply = append(*reply, "test")
return nil
}
func main() {
newServer := rpc.NewServer()
newServer.Register(new(Arith))
l, e := net.Listen("tcp", "127.0.0.1:1234") // any available address
if e != nil {
log.Fatalf("net.Listen tcp :0: %v", e)
}
go newServer.Accept(l)
newServer.HandleHTTP("/foo", "/bar")
http.ListenAndServe(":8080",newServer)
}
go newServer.Accept(l)的内部:go server.ServeConn(conn)func (server *Server) Accept(lis net.Listener) {
for {
conn, err := lis.Accept()
if err != nil {
log.Print("rpc.Serve: accept:", err.Error())
return
}
go server.ServeConn(conn)
}
}
因为rpc的Server类实现了ServHTTP方法,所以可以当作net handle来使用。并且限制了请求的http的method为connect,后面会使用curl来测试,两个相同的地方就是调用了server.ServeConn(conn)
代码如下:
func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.Method != "CONNECT" {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusMethodNotAllowed)
io.WriteString(w, "405 must CONNECT\n")
return
}
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
return
}
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
server.ServeConn(conn)
}
client.go
package main
import(
"net/rpc"
"net/http"
"log"
"net"
"fmt"
// "io/ioutil"
)
type Args struct {
A, B int
}
func main(){
// 使用tcp的方式来调用rpc
address, err := net.ResolveTCPAddr("tcp", "127.0.0.1:1234")
if err != nil {
panic(err)
}
conn, _ := net.DialTCP("tcp", nil, address)
defer conn.Close()
client := rpc.NewClient(conn)
defer client.Close()
args := &Args{7,8}
reply := make([]string, 10)
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
log.Println("rpc:",reply)
// 使用http的方式来调用rpc
cli,err:=rpc.DialHTTP("tcp","localhost:8080/bar")
if err!=nil{
fmt.Println(err)
}
err = cli.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
log.Println("http:",reply)
//使用http request请求,看服务是否异常,rpc服务会通过response的status返回
req,err:=http.NewRequest("CONNECT","http://127.0.0.1:8080/bar",nil)
if err!=nil{
fmt.Println(err)
}
httpclient := &http.Client{}
rspo,err:=httpclient.Do(req)
if err!=nil{
fmt.Println(err)
}
var by []byte
// by=make([]byte,1024)加上这句程序会阻塞
fmt.Println("status:",rspo.Status)
n,_:=rspo.Body.Read(by)
fmt.Println("http:",string(by),"n:",n)
fmt.Println("end")
}
输出结果:两种调用rpc都输出了结果,使用http request只返回了response的status,body中是没有数据的。
2016/10/28 14:16:05 rpc: [test] 2016/10/28 14:16:05 http: [test] status: 200 Connected to Go RPC http: n: 0 end
使用curl命令测试:
[baizhi@localhost ex]$ curl localhost:8080/bar 405 must CONNECT [baizhi@localhost ex]$ curl -I -X CONNECT localhost:8080/bar HTTP/1.0 200 Connected to Go RPC

浙公网安备 33010602011771号