mysql sock golang_golang thrift 总结一下网络上的一些坑
我們以hello world來大概分析一下golang中的thrift包,并且扒一扒網絡上有關thrift的一些坑
查看源碼,服務器定義如下:(詳見simple_server.go文件)
type TSimpleServer struct{
quit chanstruct{}
stopped int64
processorFactory TProcessorFactory //實質是一個handler,用來相應客戶端的請求
serverTransport TServerTransport //實質是一個socket
inputTransportFactory TTransportFactory //實質是傳輸協議的具體操作類(詳細可見transport.go文件中TTransport結構體)
outputTransportFactory TTransportFactory //
inputProtocolFactory TProtocolFactory //實質是傳輸協議(有compact、simplejson、json、binary四種協議,默認是binary)
tputProtocolFactory TProtocolFactory //
}
在go語言中,創(chuàng)建一個thrift服務器有三種方法:(詳見simple_server.go文件)
func NewTSimpleServer2(processor TProcessor, serverTransport TServerTransport) *TSimpleServer {returnNewTSimpleServerFactory2(NewTProcessorFactory(processor), serverTransport)
}
func NewTSimpleServer4(processor TProcessor, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory)*TSimpleServer {returnNewTSimpleServerFactory4(NewTProcessorFactory(processor),
serverTransport,
transportFactory,
protocolFactory,
)
}
func NewTSimpleServer6(processor TProcessor, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory)*TSimpleServer {returnNewTSimpleServerFactory6(NewTProcessorFactory(processor),
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory,
)
}
這三個函數分別調用了工廠函數
NewTSimpleServerFactory2;
NewTSimpleServerFactory4;
NewTSimpleServerFactory6;
func NewTSimpleServerFactory2(processorFactory TProcessorFactory, serverTransport TServerTransport) *TSimpleServer {returnNewTSimpleServerFactory6(processorFactory,
serverTransport,
NewTTransportFactory(),
NewTTransportFactory(),
NewTBinaryProtocolFactoryDefault(),
NewTBinaryProtocolFactoryDefault(),
)
}
func NewTSimpleServerFactory4(processorFactory TProcessorFactory, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory)*TSimpleServer {returnNewTSimpleServerFactory6(processorFactory,
serverTransport,
transportFactory,
transportFactory,
protocolFactory,
protocolFactory,
)
}
func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory)*TSimpleServer {return &TSimpleServer{
processorFactory: processorFactory,
serverTransport: serverTransport,
inputTransportFactory: inputTransportFactory,
outputTransportFactory: outputTransportFactory,
inputProtocolFactory: inputProtocolFactory,
outputProtocolFactory: outputProtocolFactory,
quit: make(chanstruct{}, 1),
}
}
好啦!現在假如我們需要創(chuàng)建一個以二進制協議傳輸的thrift服務器,那么可以用如下代碼簡單實現:
serverTransport, err := thrift.NewTServerSocket("127.0.0.1:8808")if err !=nil {
fmt.Println("Error!", err)return}
handler := &rpcService{}
processor :=rpc.NewRpcServiceProcessor(handler)
server :=thrift.NewTSimpleServer2(processor, serverTransport)
fmt.Println("thrift server in localhost")
server.Serve()
另外我在網上查看這方面資料的時候,發(fā)現大家都用的NewTSimpleServer4這個函數,然后自己又創(chuàng)建一遍NewTTransportFactory以及NewTBinaryProtocolFactoryDefault。
現在我們分析一下源碼,發(fā)現此舉實乃多此一舉。這是第一坑。
接下來說說如何用golang thrift編寫客戶端,查看網絡上的一些寫法,發(fā)現根本用不了,服務器會阻塞住!還是從源碼來分析:
在thrift自動生成的代碼中,會生成一個關于客戶端的示例。
//Autogenerated by Thrift Compiler (0.9.3)//DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package main
import ("flag"
"fmt"
"git.apache.org/thrift.git/lib/go/thrift"
"math"
"net"
"net/url"
"os"
"strconv"
"strings"
"vic/rpc")
func Usage() {
fmt.Fprintln(os.Stderr,"Usage of", os.Args[0], "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:")
flag.PrintDefaults()
fmt.Fprintln(os.Stderr,"\nFunctions:")
fmt.Fprintln(os.Stderr,"Video request(string vid, string cid, string platform, string url, string clientVersion)")
fmt.Fprintln(os.Stderr)
os.Exit(0)
}
func main() {
flag.Usage=Usagevar host string
var port int
var protocol string
var urlString string
var framed bool
var useHttp bool
varparsedUrl url.URLvartrans thrift.TTransport
_=strconv.Atoi
_=math.Abs
flag.Usage=Usage
flag.StringVar(&host, "h", "localhost", "Specify host and port")
flag.IntVar(&port, "p", 9090, "Specify port")
flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)")
flag.StringVar(&urlString, "u", "", "Specify the url")
flag.BoolVar(&framed, "framed", false, "Use framed transport")
flag.BoolVar(&useHttp, "http", false, "Use http")
flag.Parse()if len(urlString) > 0{
parsedUrl, err :=url.Parse(urlString)if err !=nil {
fmt.Fprintln(os.Stderr,"Error parsing URL:", err)
flag.Usage()
}
host=parsedUrl.Host
useHttp= len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http"}else ifuseHttp {
_, err := url.Parse(fmt.Sprint("http://", host, ":", port))if err !=nil {
fmt.Fprintln(os.Stderr,"Error parsing URL:", err)
flag.Usage()
}
}
cmd := flag.Arg(0)varerr errorifuseHttp {
trans, err=thrift.NewTHttpClient(parsedUrl.String())
}else{
portStr :=fmt.Sprint(port)if strings.Contains(host, ":") {
host, portStr, err=net.SplitHostPort(host)if err !=nil {
fmt.Fprintln(os.Stderr,"error with host:", err)
os.Exit(1)
}
}
trans, err=thrift.NewTSocket(net.JoinHostPort(host, portStr))if err !=nil {
fmt.Fprintln(os.Stderr,"error resolving address:", err)
os.Exit(1)
}ifframed {
trans=thrift.NewTFramedTransport(trans)
}
}if err !=nil {
fmt.Fprintln(os.Stderr,"Error creating transport", err)
os.Exit(1)
}
defer trans.Close()varprotocolFactory thrift.TProtocolFactoryswitchprotocol {case "compact":
protocolFactory=thrift.NewTCompactProtocolFactory()break
case "simplejson":
protocolFactory=thrift.NewTSimpleJSONProtocolFactory()break
case "json":
protocolFactory=thrift.NewTJSONProtocolFactory()break
case "binary", "":
protocolFactory=thrift.NewTBinaryProtocolFactoryDefault()break
default:
fmt.Fprintln(os.Stderr,"Invalid protocol specified:", protocol)
Usage()
os.Exit(1)
}
client :=rpc.NewVideoServiceClientFactory(trans, protocolFactory)if err := trans.Open(); err !=nil {
fmt.Fprintln(os.Stderr,"Error opening socket to", host, ":", port, " ", err)
os.Exit(1)
}switchcmd {case "request":if flag.NArg()-1 != 5{
fmt.Fprintln(os.Stderr,"Request requires 5 args")
flag.Usage()
}
argvalue0 := flag.Arg(1)
value0 :=argvalue0
argvalue1 := flag.Arg(2)
value1 :=argvalue1
argvalue2 := flag.Arg(3)
value2 :=argvalue2
argvalue3 := flag.Arg(4)
value3 :=argvalue3
argvalue4 := flag.Arg(5)
value4 :=argvalue4
fmt.Print(client.Request(value0, value1, value2, value3, value4))
fmt.Print("\n")break
case "":
Usage()break
default:
fmt.Fprintln(os.Stderr,"Invalid function", cmd)
}
}
View Code
我們一部分一部分來分析分析:
flag.Usage =Usagevar host string
var port int
var protocol string
var urlString string
var framed bool
var useHttp bool
varparsedUrl url.URLvartrans thrift.TTransport
_=strconv.Atoi
_=math.Abs
flag.Usage=Usage
flag.StringVar(&host, "h", "localhost", "Specify host and port")
flag.IntVar(&port, "p", 9090, "Specify port")
flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)")
flag.StringVar(&urlString, "u", "", "Specify the url")
flag.BoolVar(&framed, "framed", false, "Use framed transport")
flag.BoolVar(&useHttp, "http", false, "Use http")
flag.Parse()
這些代碼是設置了一些程序的啟動命令,例如默認地址是loacalhost,我們可以根據client.exe -h xxx.xxx.xxx.xxx之類的命令來修改
我們發(fā)現這些代碼都不是我們需要的,pass,繼續(xù)看
if len(urlString) > 0{
parsedUrl, err :=url.Parse(urlString)if err !=nil {
fmt.Fprintln(os.Stderr,"Error parsing URL:", err)
flag.Usage()
}
host=parsedUrl.Host
useHttp= len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http"}else ifuseHttp {
_, err := url.Parse(fmt.Sprint("http://", host, ":", port))if err !=nil {
fmt.Fprintln(os.Stderr,"Error parsing URL:", err)
flag.Usage()
}
}
cmd := flag.Arg(0)varerr errorifuseHttp { trans, err = thrift.NewTHttpClient(parsedUrl.String())}else{
portStr :=fmt.Sprint(port)if strings.Contains(host, ":") {
host, portStr, err=net.SplitHostPort(host)if err !=nil {
fmt.Fprintln(os.Stderr,"error with host:", err)
os.Exit(1)
}
}
trans, err= thrift.NewTSocket(net.JoinHostPort(host, portStr))
if err !=nil {
fmt.Fprintln(os.Stderr,"error resolving address:", err)
os.Exit(1)
}ifframed {
trans=thrift.NewTFramedTransport(trans)
}
}
這部分主要作用是解析url參數,從中取得host以及port。并且用于生成一個TTransport,上面紅線加粗的函數定義在源碼中如下:
func NewTHttpClient(urlstr string) (TTransport, error) {returnNewTHttpClientWithOptions(urlstr, THttpClientOptions{})
}
func NewTSocket(hostPortstring) (*TSocket, error) {return NewTSocketTimeout(hostPort, 0)
}
細心的朋友們可能發(fā)現了端倪,第二個函數的返回值是一個TSocket指針,并不是TTransport,是不是有啥問題?不急,我們看看這兩個結構體的定義就知道了:
type TTransport interface{
io.ReadWriteCloser
Flusher
ReadSizeProvider//Opens the transport for communication
Open() error//Returns true if the transport is open
IsOpen() bool}
原來TTransport是一個接口類型,而TSocket則實現了該接口!
目前為止,我們獲得了創(chuàng)建客戶端所需要的關鍵代碼:
trans, err =thrift.NewTHttpClient(parsedUrl.String())
trans, err= thrift.NewTSocket(net.JoinHostPort(host, portStr))
OK,繼續(xù)分析示例!
varprotocolFactory thrift.TProtocolFactoryswitchprotocol {case "compact":
protocolFactory=thrift.NewTCompactProtocolFactory()break
case "simplejson":
protocolFactory=thrift.NewTSimpleJSONProtocolFactory()break
case "json":
protocolFactory=thrift.NewTJSONProtocolFactory()break
case "binary", "":
protocolFactory=thrift.NewTBinaryProtocolFactoryDefault()break
default:
fmt.Fprintln(os.Stderr,"Invalid protocol specified:", protocol)
Usage()
os.Exit(1)
}
client := rpc.NewVideoServiceClientFactory(trans, protocolFactory)if err := trans.Open(); err !=nil {
fmt.Fprintln(os.Stderr,"Error opening socket to", host, ":", port, " ", err)
os.Exit(1)
}
switch語句是根據我們所輸入的參數,選擇傳輸協議。最后通過NewVideoServiceClientFactory函數 完成客戶端的創(chuàng)建
最后,總結一下,假如我們要創(chuàng)建一個以二進制為傳輸協議,那么我們可以編寫如下代碼來完成:
transport, err := thrift.NewTSocket(net.JoinHostPort("127.0.0.1", "8808"))if err !=nil {
fmt.Fprintln(os.Stderr,"error resolving address:", err)
os.Exit(1)
}
protocolFactory :=thrift.NewTBinaryProtocolFactoryDefault()
client :=NewRpcServiceClientFactory(transport, protocolFactory)if err := transport.Open(); err !=nil {
fmt.Fprintln(os.Stderr,"Error opening socket to 127.0.0.1:8808", " ", err)
os.Exit(1)
}
defer transport.Close()
res, _ := client.SayHi(“World”)
有疑問加站長微信聯系(非本文作者)
總結
以上是生活随笔為你收集整理的mysql sock golang_golang thrift 总结一下网络上的一些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符b是多少java_Java学习,对比
- 下一篇: java读取属性文件的方法_java读取