再次思考一下go网络包中的接口设计
Posted 柳清风09
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再次思考一下go网络包中的接口设计相关的知识,希望对你有一定的参考价值。
我们经常使用的http包,无论是客户端还是服务端,都有很多值得推敲的地方。
首先是服务端设计;上上篇 我们通过监听一个UDS提供一个http服务,代码大概是这样的
unixListener, err := net.Listen("unix", os.Args[1])
if err != nil
panic(err)
server.Serve(unixListener)
这里创建一个listener,然后交给serve去处理。这就体现了接口的作用,把监听交给服务去处理,这里监听其实只要实现着下面三个接口就行
type Listener interface
// Accept waits for and returns the next connection to the listener.
Accept() (Conn, error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
Addr() Addr
其中最重要的就是Accept。接收请求,交给serve去处理。同理如果是监听vscok也可以,譬如下面的代码。
l, err := vsock.Listen(1025)
// Create SOCKS5 proxy on vsock
if err := server.Serve(l); err != nil
panic(err)
也是一样,实现accept的方法的vscok同样可以作为接收器交给serve去处理。那server具体干怎么处理了?不用想也可知道,就是从accept里面获取请求,然后启动go 协程处理。譬如github.com/armon/go-socks5中Serve的代码
func (s *Server) Serve(l net.Listener) error
for
conn, err := l.Accept()
if err != nil
return err
go s.ServeConn(conn)
return nil
如果是http Serve其实也是类似的。
这里顺便说一下,我们经常使用的ListenAndServe这个方法,这个方法名副其实,就是把listen和serve放到一起了。先listen后serve。
func (s *Server) ListenAndServe(network, addr string) error
l, err := net.Listen(network, addr)
if err != nil
return err
return s.Serve(l)
我们再来看看客户端的代码,我们都知道http底层是tcp。tcp如何建立连接这部分是通过DialContext实现的
// DialContext specifies the dial function for creating unencrypted TCP connections.
// If DialContext is nil (and the deprecated Dial below is also nil),
// then the transport dials using package net.
//
// DialContext runs concurrently with calls to RoundTrip.
// A RoundTrip call that initiates a dial may end up using
// a connection dialed previously when the earlier connection
// becomes idle before the later DialContext completes.
DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
如果我们需要实现自定义的tcp连接,我们可以自己去实现,还是回到之前UDS的例子
httpc := http.Client
Transport: &http.Transport
DialContext: func(_ context.Context, _, _ string) (net.Conn, error)
return net.Dial("unix", flag.Args()[0]) //uds 路径
,
,
我们通过 net.Dial(“unix”) 建立UDS的tcp连接。如果是我们自己可以基于sock5协议实现一个dail方法,去代理我们的请求,我们就可以这样实现。
func (sf *Client) Dial(network, addr string) (net.Conn, error)
if network == "tcp"
return sf.DialTCP(network, addr)
if network == "udp"
return sf.DialUDP(network, nil, addr)
return nil, errors.New("not support network")
然后便可以直接使用
httpClient := http.Client
Transport: &http.Transport
DialContext: func(ctx context.Context, protocl, addr string) (net.Conn, error)
return client.Dial(protocl, addr)
,
,
注意,这里的protocl 已经解析成tcp或者udp协议了。
接口让世界更美好!
以上是关于再次思考一下go网络包中的接口设计的主要内容,如果未能解决你的问题,请参考以下文章