- rpc
- rpc/jsonrpc
- smtp
- textproto
- url
本包大部分都遵守RFC 5322规定的语法,值得注意的区别是:
* 旧格式地址和嵌入远端信息的地址不会被解析
* 组地址不会被解析
* 不支持全部的间隔符(CFWS语法元素),如分属两行的地址
Variables
var ErrHeaderNotPresent = errors.New("mail: header not in message")
type Address
type Address struct {
Name string // 固有名,可以为空
Address string // user@domain
}
Address类型表示一个邮箱地址。
例如地址"Barry Gibbs bg@example.com"表示为Address{Name: "Barry Gibbs", Address: "bg@example.com"}
func ParseAddress
func ParseAddress(address string) (*Address, error)
解析单个的RFC 5322地址,例如"Barry Gibbs bg@example.com"。
func (*Address) String
func (a *Address) String() string
func ParseAddressList
func ParseAddressList(list string) ([]*Address, error)
函数将list作为一串邮箱地址并解析返回。
type Header
type Header map[string][]string
Header代表邮件头域的多个键值对。
func (Header) AddressList
func (h Header) AddressList(key string) ([]*Address, error)
将键key对应的值(字符串)作为邮箱地址列表解析并返回。
func (Header) Date
func (h Header) Date() (time.Time, error)
解析头域Date项的值并返回。
func (Header) Get
func (h Header) Get(key string) string
返回键key对应的第一个值,如果没有对应值,将返回空字符串。
type Message
type Message struct {
Header Header
Body io.Reader
}
Message代表一个解析后的邮件。
func ReadMessage
func ReadMessage(r io.Reader) (msg *Message, err error)
从r读取一个邮件,会解析邮件头域,消息主体可以从r/msg.Body中读取。
RPC
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。
只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
- 方法是导出的
- 方法有两个参数,都是导出类型或内建类型
- 方法的第二个参数是指针
- 方法只有一个error接口类型的返回值
事实上,方法必须看起来像这样:
func (t *T) MethodName(argType T1, replyType *T2) error
其中T、T1和T2都能被encoding/gob包序列化。这些限制即使使用不同的编解码器也适用。(未来,对定制的编解码器可能会使用较宽松一点的限制)
方法的第一个参数代表调用者提供的参数;第二个参数代表返回给调用者的参数。方法的返回值,如果非nil,将被作为字符串回传,在客户端看来就和errors.New创建的一样。如果返回了错误,回复的参数将不会被发送给客户端。
服务端可能会单个连接上调用ServeConn管理请求。更典型地,它会创建一个网络监听器然后调用Accept;或者,对于HTTP监听器,调用HandleHTTP和http.Serve。
想要使用服务的客户端会创建一个连接,然后用该连接调用NewClient。
更方便的函数Dial(DialHTTP)会在一个原始的连接(或HTTP连接)上依次执行这两个步骤。
生成的Client类型值有两个方法,Call和Go,它们的参数为要调用的服务和方法、一个包含参数的指针、一个用于接收接个的指针。
Call方法会等待远端调用完成,而Go方法异步的发送调用请求并使用返回的Call结构体类型的Done通道字段传递完成信号。
除非设置了显式的编解码器,本包默认使用encoding/gob包来传输数据。
这是一个简单的例子。一个服务端想要导出Arith类型的一个对象:
package server
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
type Arith int
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
服务端会调用(用于HTTP服务):
arith := new(Arith)
rpc.Register(arith)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
go http.Serve(l, nil)
此时,客户端可看到服务"Arith"及它的方法"Arith.Multiply"、"Arith.Divide"。要调用方法,客户端首先呼叫服务端:
client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
if err != nil {
log.Fatal("dialing:", err)
}
然后,客户端可以执行远程调用:
// Synchronous call
args := &server.Args{7,8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
或:
// Asynchronous call
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := <-divCall.Done // will be equal to divCall
// check errors, print, etc.
服务端的实现应为客户端提供简单、类型安全的包装。
Constants
const (
// HandleHTTP使用的默认值
DefaultRPCPath = "/_goRPC_"
DefaultDebugPath = "/debug/rpc"
)
Variables
var DefaultServer = NewServer()
DefaultServer是*Server的默认实例,本包和Server方法同名的函数都是对其方法的封装。
var ErrShutdown = errors.New("connection is shut down")
type ServerError
type ServerError string
ServerError表示已从RPC连接的远程端返回的错误。
func (ServerError) Error
func (e ServerError) Error() string
type Request
type Request struct {
ServiceMethod string // 格式:"Service.Method"
Seq uint64 // 由客户端选择的序列号
// 内含隐藏或非导出字段
}
Request是每个RPC调用请求的头域。它是被内部使用的,这里的文档用于帮助debug,如分析网络拥堵时。
type Response
type Response struct {
ServiceMethod string // 对应请求的同一字段
Seq uint64 // 对应请求的同一字段
Error string // 可能的错误
// 内含隐藏或非导出字段
}
Response是每个RPC调用回复的头域。它是被内部使用的,这里的文档用于帮助debug,如分析网络拥堵时。
type ClientCodec
type ClientCodec interface {
// 本方法必须能安全的被多个go程同时使用
WriteRequest(*Request, interface{}) error
ReadResponseHeader(*Response) error
ReadResponseBody(interface{}) error
Close() error
}
ClientCodec接口实现了RPC会话的客户端一侧RPC请求的写入和RPC回复的读取。客户端调用WriteRequest来写入请求到连接,然后成对调用ReadRsponseHeader和ReadResponseBody以读取回复。客户端在结束该连接的事务时调用Close方法。ReadResponseBody可以使用nil参数调用,以强制回复的主体被读取然后丢弃。
type ServerCodec
type ServerCodec interface {
ReadRequestHeader(*Request) error
ReadRequestBody(interface{}) error
// 本方法必须能安全的被多个go程同时使用
WriteResponse(*Response, interface{}) error
Close() error
}
ServerCodec接口实现了RPC会话的服务端一侧RPC请求的读取和RPC回复的写入。服务端通过成对调用方法ReadRequestHeader和ReadRequestBody从连接读取请求,然后调用WriteResponse来写入回复。服务端在结束该连接的事务时调用Close方法。ReadRequestBody可以使用nil参数调用,以强制请求的主体被读取然后丢弃。
type Call
type Call struct {
ServiceMethod string // 调用的服务和方法的名称
Args interface{} // 函数的参数(下层为结构体指针)
Reply interface{} // 函数的回复(下层为结构体指针)
Error error // 在调用结束后,保管错误的状态
Done chan *Call // 对其的接收操作会阻塞,直到远程调用结束
}
Call类型代表一个执行中/执行完毕的RPC会话。
type Client
type Client struct {
// 内含隐藏或非导出字段
}
Client类型代表RPC客户端。同一个客户端可能有多个未返回的调用,也可能被多个go程同时使用。
func NewClient
func NewClient(conn io.ReadWriteCloser) *Client
NewClient返回一个新的Client,以管理对连接另一端的服务的请求。它添加缓冲到连接的写入侧,以便将回复的头域和有效负载作为一个单元发送。
func NewClientWithCodec
func NewClientWithCodec(codec ClientCodec) *Client
NewClientWithCodec类似NewClient,但使用指定的编解码器,以编码请求主体和解码回复主体。
func Dial
func Dial(network, address string) (*Client, error)
Dial在指定的网络和地址与RPC服务端连接。
func DialHTTP
func DialHTTP(network, address string) (*Client, error)
DialHTTP在指定的网络和地址与在默认HTTP RPC路径监听的HTTP RPC服务端连接。
func DialHTTPPath
func DialHTTPPath(network, address, path string) (*Client, error)
DialHTTPPath在指定的网络、地址和路径与HTTP RPC服务端连接。
func (*Client) Call
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
Call调用指定的方法,等待调用返回,将结果写入reply,然后返回执行的错误状态。
func (*Client) Go
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call
Go异步的调用函数。本方法Call结构体类型指针的返回值代表该次远程调用。通道类型的参数done会在本次调用完成时发出信号(通过返回本次Go方法的返回值)。如果done为nil,Go会申请一个新的通道(写入返回值的Done字段);如果done非nil,done必须有缓冲,否则Go方法会故意崩溃。
func (*Client) Close
func (client *Client) Close() error
type Server
type Server struct {
// 内含隐藏或非导出字段
}
Server代表RPC服务端。
func NewServer
func NewServer() *Server
NewServer创建并返回一个*Server。
func (*Server) Register
func (server *Server) Register(rcvr interface{}) error
Register在server注册并公布rcvr的方法集中满足如下要求的方法:
- 方法是导出的
- 方法有两个参数,都是导出类型或内建类型
- 方法的第二个参数是指针
- 方法只有一个error接口类型的返回值
如果rcvr不是一个导出类型的值,或者该类型没有满足要求的方法,Register会返回错误。Register也会使用log包将错误写入日志。客户端可以使用格式为"Type.Method"的字符串访问这些方法,其中Type是rcvr的具体类型。
func (*Server) RegisterName
func (server *Server) RegisterName(name string, rcvr interface{}) error
RegisterName类似Register,但使用提供的name代替rcvr的具体类型名作为服务名。
func (*Server) Accept
func (server *Server) Accept(lis net.Listener)
Accept接收监听器l获取的连接,然后服务每一个连接。Accept会阻塞,调用者应另开线程:"go server.Accept(l)"
func (*Server) ServeConn
func (server *Server) ServeConn(conn io.ReadWriteCloser)
ServeConn在单个连接上执行server。ServeConn会阻塞,服务该连接直到客户端挂起。调用者一般应另开线程调用本函数:"go server.ServeConn(conn)"。ServeConn在该连接使用gob(参见encoding/gob包)有线格式。要使用其他的编解码器,可调用ServeCodec方法。
func (*Server) ServeCodec
func (server *Server) ServeCodec(codec ServerCodec)
ServeCodec类似ServeConn,但使用指定的编解码器,以编码请求主体和解码回复主体。
func (*Server) ServeRequest
func (server *Server) ServeRequest(codec ServerCodec) error
ServeRequest类似ServeCodec,但异步的服务单个请求。它不会在调用结束后关闭codec。
func (*Server) ServeHTTP
func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP实现了回应RPC请求的http.Handler接口。
func (*Server) HandleHTTP
func (server *Server) HandleHTTP(rpcPath, debugPath string)
HandleHTTP注册server的RPC信息HTTP处理器对应到rpcPath,注册server的debug信息HTTP处理器对应到debugPath。HandleHTTP会注册到http.DefaultServeMux。之后,仍需要调用http.Serve(),一般会另开线程:"go http.Serve(l, nil)"
func Register
func Register(rcvr interface{}) error
Register在DefaultServer注册并公布rcvr的方法。
func RegisterName
func RegisterName(name string, rcvr interface{}) error
RegisterName函数类似Register函数,但使用提供的name代替rcvr的具体类型名作为服务名。
func Accept
func Accept(lis net.Listener)
Accept接收监听器l获取的连接,然后将每一个连接交给DefaultServer服务。Accept会阻塞,调用者应另开线程:"go server.Accept(l)"
func ServeConn
func ServeConn(conn io.ReadWriteCloser)
ServeConn在单个连接上执行DefaultServer。ServeConn会阻塞,服务该连接直到客户端挂起。调用者一般应另开线程调用本函数:"go ServeConn(conn)"。ServeConn在该连接使用gob(参见encoding/gob包)有线格式。要使用其他的编解码器,可调用ServeCodec方法。
func ServeCodec
func ServeCodec(codec ServerCodec)
ServeCodec类似ServeConn,但使用指定的编解码器,以编码请求主体和解码回复主体。
func ServeRequest
func ServeRequest(codec ServerCodec) error
ServeRequest类似ServeCodec,但异步的服务单个请求。它不会在调用结束后关闭codec。
func HandleHTTP
func HandleHTTP()
HandleHTTP函数注册DefaultServer的RPC信息HTTP处理器对应到DefaultRPCPath,和DefaultServer的debug处理器对应到DefaultDebugPath。HandleHTTP函数会注册到http.DefaultServeMux。之后,仍需要调用http.Serve(),一般会另开线程:"go http.Serve(l, nil)"
rpc/jsonrpc
jsonrpc包实现了JSON-RPC的ClientCodec和ServerCodec接口,可用于rpc包。
func Dial
func Dial(network, address string) (*rpc.Client, error)
Dial在指定的网络和地址连接一个JSON-RPC服务端。
func NewClient
func NewClient(conn io.ReadWriteCloser) *rpc.Client
NewClient返回一个新的rpc.Client,以管理对连接另一端的服务的请求。
func NewClientCodec
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec
NewClientCodec返回一个在连接上使用JSON-RPC的rpc.ClientCodec。
func NewServerCodec
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec
NewServerCodec返回一个在连接上使用JSON-RPC的rpc. ServerCodec。
func ServeConn
func ServeConn(conn io.ReadWriteCloser)
ServeConn在单个连接上执行DefaultServer。ServeConn会阻塞,服务该连接直到客户端挂起。调用者一般应另开线程调用本函数:"go serveConn(conn)"。ServeConn在该连接使用JSON编解码格式。
smtp
smtp包实现了简单邮件传输协议(SMTP),参见RFC 5321。同时本包还实现了如下扩展:
8BITMIME RFC 1652
AUTH RFC 2554
STARTTLS RFC 3207
客户端可以自行管理其他的扩展。
// Connect to the remote SMTP server.
c, err := smtp.Dial("mail.example.com:25")
if err != nil {
log.Fatal(err)
}
// Set the sender and recipient first
if err := c.Mail("sender@example.org"); err != nil {
log.Fatal(err)
}
if err := c.Rcpt("recipient@example.net"); err != nil {
log.Fatal(err)
}
// Send the email body.
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
_, err = fmt.Fprintf(wc, "This is the email body")
if err != nil {
log.Fatal(err)
}
err = wc.Close()
if err != nil {
log.Fatal(err)
}
// Send the QUIT command and close the connection.
err = c.Quit()
if err != nil {
log.Fatal(err)
}
type ServerInfo
type ServerInfo struct {
Name string // SMTP服务器的名字
TLS bool // Name有合法的证书并使用TLS时为真
Auth []string // 支持的认证机制
}
ServerInfo类型记录一个SMTP服务器的信息。
type Auth
type Auth interface {
// 方法开始和服务端的认证。
// 它返回认证协议的名字和可能有的应发送给服务端的包含初始认证信息的数据。
// 如果返回值proto == "",表示应跳过认证;
// 如果返回一个非nil的错误,SMTP客户端应中断认证身份的尝试并关闭连接。
Start(server *ServerInfo) (proto string, toServer []byte, err error)
// 方法继续认证过程。fromServer为服务端刚发送的数据。
// 如果more为真,服务端会期望一个回复,回复内容应被Next返回,即toServer;
// 否则返回值toServer应为nil。
// 如果返回一个非nil的错误,SMTP客户端应中断认证身份的尝试并关闭连接。
Next(fromServer []byte, more bool) (toServer []byte, err error)
}
Auth接口应被每一个SMTP认证机制实现。
func CRAMMD5Auth
func CRAMMD5Auth(username, secret string) Auth
返回一个实现了CRAM-MD5身份认证机制(参见RFC 2195)的Auth接口。返回的接口使用给出的用户名和密码,采用响应——回答机制与服务端进行身份认证。
func PlainAuth
func PlainAuth(identity, username, password, host string) Auth
返回一个实现了PLAIN身份认证机制(参见RFC 4616)的Auth接口。返回的接口使用给出的用户名和密码,通过TLS连接到主机认证,采用identity为身份管理和行动(通常应设identity为"",以便使用username为身份)。
// Set up authentication information.
auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
to := []string{"recipient@example.net"}
msg := []byte("This is the email body.")
err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
if err != nil {
log.Fatal(err)
}
type Client
type Client struct {
// 代表被Client使用的textproto.Conn,它可以导出,以便使用者添加扩展。
Text *textproto.Conn
// 内含隐藏或非导出字段
}
Client代表一个连接到SMTP服务器的客户端。
func Dial
func Dial(addr string) (*Client, error)
Dial返回一个连接到地址为addr的SMTP服务器的*Client;addr必须包含端口号。
func NewClient
func NewClient(conn net.Conn, host string) (*Client, error)
NewClient使用已经存在的连接conn和作为服务器名的host(用于身份认证)来创建一个*Client。
func (*Client) Extension
func (c *Client) Extension(ext string) (bool, string)
Extension返回服务端是否支持某个扩展,扩展名是大小写不敏感的。如果扩展被支持,方法还会返回一个包含指定给该扩展的各个参数的字符串。
func (*Client) Hello
func (c *Client) Hello(localName string) error
Hello发送给服务端一个HELO或EHLO命令。本方法只有使用者需要控制使用的本地主机名时才应使用,否则程序会将本地主机名设为“localhost”,Hello方法只能在最开始调用。
func (*Client) Auth
func (c *Client) Auth(a Auth) error
Auth使用提供的认证机制进行认证。失败的认证会关闭该连接。只有服务端支持AUTH时,本方法才有效。(但是不支持时,调用会默默的成功)
func (*Client) Verify
func (c *Client) Verify(addr string) error
Verify检查一个邮箱地址在其服务器是否合法,如果合法会返回nil;但非nil的返回值并不代表不合法,因为许多服务器出于安全原因不支持这种查询。
func (*Client) StartTLS
func (c *Client) StartTLS(config *tls.Config) error
StartTLS方法发送STARTTLS命令,并将之后的所有数据往来加密。只有服务器附加了STARTTLS扩展,这个方法才有效。
func (*Client) Mail
func (c *Client) Mail(from string) error
Mail发送MAIL命令和邮箱地址from到服务器。如果服务端支持8BITMIME扩展,本方法会添加BODY=8BITMIME参数。方法初始化一次邮件传输,后应跟1到多个Rcpt方法的调用。
func (*Client) Rcpt
func (c *Client) Rcpt(to string) error
Rcpt发送RCPT命令和邮箱地址to到服务器。调用Rcpt方法之前必须调用了Mail方法,之后可以再一次调用Rcpt方法,也可以调用Data方法。
func (*Client) Data
func (c *Client) Data() (io.WriteCloser, error)
Data发送DATA指令到服务器并返回一个io.WriteCloser,用于写入邮件信息。调用者必须在调用c的下一个方法之前关闭这个io.WriteCloser。方法必须在一次或多次Rcpt方法之后调用。
func (*Client) Reset
func (c *Client) Reset() error
Reset向服务端发送REST命令,中断当前的邮件传输。
func (*Client) Quit
func (c *Client) Quit() error
Quit发送QUIT命令并关闭到服务端的连接。
func (*Client) Close
func (c *Client) Close() error
Close关闭连接。
func SendMail
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error
SendMail连接到addr指定的服务器;如果支持会开启TLS;如果支持会使用a认证身份;然后以from为邮件源地址发送邮件msg到目标地址to。(可以是多个目标地址:群发)
textproto
textproto实现了对基于文本的请求/回复协议的一般性支持,包括HTTP、NNTP和SMTP。
本包提供:
错误,代表服务端回复的错误码。Pipeline,以管理客户端中的管道化的请求/回复。Reader,读取数值回复码行,键值对形式的头域,一个作为后续行先导的空行,以及以只有一个"."的一行为结尾的整个文本块。Writer,写入点编码的文本。Conn,对Reader、Writer和Pipline的易用的包装,用于单个网络连接。
type ProtocolError
type ProtocolError string
ProtocolError描述一个违反协议的错误,如不合法的回复或者挂起的连接。
func (ProtocolError) Error
func (p ProtocolError) Error() string
type Error
type Error struct {
Code int
Msg string
}
Error代表一个服务端返回的数值状态码/错误码。
func (*Error) Error
func (e *Error) Error() string
func CanonicalMIMEHeaderKey
func CanonicalMIMEHeaderKey(s string) string
返回一个MIME头的键的规范格式。该标准会将首字母和所有"-"之后的字符改为大写,其余字母改为小写。举个例子,"accept-encoding"作为键的标准格式是"Accept-Encoding"。MIME头的键必须是ASCII码构成。
func TrimBytes
func TrimBytes(b []byte) []byte
去掉b前后的ASCII码空白(不去Unicode空白)
func TrimString
func TrimString(s string) string
去掉s前后的ASCII码空白(不去Unicode空白)
type MIMEHeader
type MIMEHeader map[string][]string
MIMEHeader代表一个MIME头,将键映射为值的集合。
func (MIMEHeader) Get
func (h MIMEHeader) Get(key string) string
Get方法返回键对应的值集的第一个值。如果键没有关联值,返回""。如要获得键对应的值集直接用map。
func (MIMEHeader) Set
func (h MIMEHeader) Set(key, value string)
Set方法将键对应的值集设置为只含有value一个值。没有就新建,有则删掉原有的值。
func (MIMEHeader) Add
func (h MIMEHeader) Add(key, value string)
Add方法向h中添加键值对,它会把新的值添加到键对应的值的集合里。
func (MIMEHeader) Del
func (h MIMEHeader) Del(key string)
Del方法删除键对应的值集。
type Reader
type Reader struct {
R *bufio.Reader
// 内含隐藏或非导出字段
}
Reader实现了从一个文本协议网络连接中方便的读取请求/回复的方法。
func NewReader
func NewReader(r *bufio.Reader) *Reader
NewReader返回一个从r读取数据的Reader。
func (*Reader) DotReader
func (r *Reader) DotReader() io.Reader
DotReader方法返回一个io.Reader,该接口自动解码r中读取的点编码块。注意该接口仅在下一次调用r的方法之前才有效。点编码是文本协议如SMTP用于文本块的通用框架。数据包含多个行,每行以"\r\n"结尾。数据本身以一个只含有一个点的一行".\r\n"来结尾。以点起始的行会添加额外的点,来避免看起来像是文本的结尾。
返回接口的Read方法会将行尾的"\r\n"修改为"\n",去掉起头的转义点,并在底层读取到(并抛弃掉)表示文本结尾的行时停止解码并返回io.EOF错误。
func (*Reader) ReadLine
func (r *Reader) ReadLine() (string, error)
ReadLine方法从r读取单行,去掉最后的\r\n或\n。
func (*Reader) ReadLineBytes
func (r *Reader) ReadLineBytes() ([]byte, error)
ReadLineBytes类似ReadLine但返回[]byte切片。
func (*Reader) ReadContinuedLine
func (r *Reader) ReadContinuedLine() (string, error)
ReadContinuedLine从r中读取可能有后续的行,会将该行尾段的ASCII空白剔除,并将该行后面所有以空格或者tab起始的行视为其后续,后续部分会剔除行头部的空白,所有这些行包括第一行以单个空格连接起来返回。
举例如下:
Line 1
continued...
Line 2
第一次调用ReadContinuedLine会返回"Line 1 continued...",第二次会返回"Line 2"
只有空格的行不被视为有后续的行。
func (*Reader) ReadContinuedLineBytes
func (r *Reader) ReadContinuedLineBytes() ([]byte, error)
ReadContinuedLineBytes类似ReadContinuedLine但返回[]byte切片。
func (*Reader) ReadDotBytes
func (r *Reader) ReadDotBytes() ([]byte, error)
ReadDotBytes读取点编码文本返回解码后的数据,点编码详见DotReader方法。
func (*Reader) ReadDotLines
func (r *Reader) ReadDotLines() ([]string, error)
ReadDotLines方法读取一个点编码文本块并返回一个包含解码后各行的切片,各行最后的\r\n或\n去掉。
func (*Reader) ReadCodeLine
func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error)
方法读取回复的状态码行,格式如下:
code message
状态码是3位数字,message进一步描述状态,例如:
220 plan9.bell-labs.com ESMTP
如果状态码字符串的前缀不匹配expectCode,方法返回错误&Error{code, message}。例如expectCode是31,则如果状态码不在区间[310, 319]内就会返回错误。如果回复是多行的则会返回错误。
如果expectCode <= 0,将不会检查状态码。
func (*Reader) ReadResponse
func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error)
ReadResponse方法读取如下格式的多行回复:
code-message line 1
code-message line 2
...
code message line n
其中code是三位数的状态码。第一行以code和连字符开始,最后以同code后跟空格的行结束。返回值message每行以\n分隔。细节参见RFC 959(http://www.ietf.org/rfc/rfc959.txt)第36页。
如果状态码字符串的前缀不匹配expectCode,方法返回时err设为&Error{code, message}。例如expectCode是31,则如果状态码不在区间[310, 319]内就会返回错误。如果回复是多行的则会返回错误。
如果expectCode <= 0,将不会检查状态码。
func (*Reader) ReadMIMEHeader
func (r *Reader) ReadMIMEHeader() (MIMEHeader, error)
ReadMIMEHeader从r读取MIME风格的头域。该头域包含一系列可能有后续的键值行,以空行结束。返回的map映射CanonicalMIMEHeaderKey(key)到值的序列(顺序与输入相同)。
举例如下:
My-Key: Value 1
Long-Key: Even
Longer Value
My-Key: Value 2
对此输入,ReadMIMEHeader返回:
map[string][]string{
"My-Key": {"Value 1", "Value 2"},
"Long-Key": {"Even Longer Value"},
}
type Writer
type Writer struct {
W *bufio.Writer
// 内含隐藏或非导出字段
}
Writer实现了方便的方法在一个文本协议网络连接中写入请求/回复。
func NewWriter
func NewWriter(w *bufio.Writer) *Writer
NewWriter函数返回一个底层写入w的Writer。
func (*Writer) DotWriter
func (w *Writer) DotWriter() io.WriteCloser
DotWriter方法返回一个io.WriteCloser,用于将点编码文本写入w。返回的接口会在必要时添加转义点,将行尾的\n替换为\r\n,并在关闭时添加最后的.\r\n行。调用者必须在下一次调用w的方法前关闭该接口。点编码文本格式参见Reader.DotReader方法。
func (*Writer) PrintfLine
func (w *Writer) PrintfLine(format string, args ...interface{}) error
PrintfLine方法将格式化的输出写入底层并在最后写入\r\n。
type Pipeline
type Pipeline struct {
// 内含隐藏或非导出字段
}
Pipeline管理管道化的有序请求/回复序列。
为了使用Pipeline管理一个连接的多个客户端,每个客户端应像下面一样运行:
id := p.Next() // 获取一个数字id
p.StartRequest(id) // 等待轮到该id发送请求
«send request»
p.EndRequest(id) // 通知Pipeline请求发送完毕
p.StartResponse(id) // 等待该id读取回复
«read response»
p.EndResponse(id) // 通知Pipeline回复已经读取
一个管道化的服务器可以使用相同的调用来保证回复并行的生成并以正确的顺序写入。
func (*Pipeline) Next
func (p *Pipeline) Next() uint
返回下一对request/response的id。
func (*Pipeline) StartRequest
func (p *Pipeline) StartRequest(id uint)
阻塞程序,直到轮到给定id来发送(读取)request。
func (*Pipeline) StartResponse
func (p *Pipeline) StartResponse(id uint)
阻塞程序,直到轮到给定id来读取(发送)response。
func (*Pipeline) EndRequest
func (p *Pipeline) EndRequest(id uint)
通知p,给定id的request的操作已经结束了。
func (*Pipeline) EndResponse
func (p *Pipeline) EndResponse(id uint)
通知p,给定id的response的操作已经结束了。
type Conn
type Conn struct {
Reader
Writer
Pipeline
// 内含隐藏或非导出字段
}
Conn代表一个文本网络协议的连接。它包含一个Reader和一个Writer来管理读写,一个Pipeline来对连接中并行的请求进行排序。匿名嵌入的类型字段是Conn可以调用它们的方法。
func NewConn
func NewConn(conn io.ReadWriteCloser) *Conn
NewConn函数返回以I/O为底层的Conn。
func Dial
func Dial(network, addr string) (*Conn, error)
Dial函数使用net.Dial在给定网络上和给定地址建立网络连接,并返回用于该连接的Conn。
func (*Conn) Cmd
func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error)
Cmd方法用于在管道中等待轮到它执行,并发送命令。命令文本是用给定的format字符串和参数格式化生成的。并会在最后添加上\r\n。Cmd函数返回该命令的Pipeline id,用于StartResponse和EndResponse方法。
例如,一个客户端可以使用如下代码执行HELP命令并返回解码后的点编码文本:
id, err := c.Cmd("HELP")
if err != nil {
return nil, err
}
c.StartResponse(id)
defer c.EndResponse(id)
if _, _, err = c.ReadCodeLine(110); err != nil {
return nil, err
}
text, err := c.ReadDotBytes()
if err != nil {
return nil, err
}
return c.ReadCodeLine(250)
func (*Conn) Close
func (c *Conn) Close() error
Close方法关闭连接。
Bugs
☞为了让调用者处理拒绝服务攻击,Reader接口应该允许他们设置和重设从连接读取的字节数。
url
url包解析URL并实现了查询的逸码,参见RFC 3986。
func QueryEscape
func QueryEscape(s string) string
QueryEscape函数对s进行转码使之可以安全的用在URL查询里。
func QueryUnescape
func QueryUnescape(s string) (string, error)
QueryUnescape函数用于将QueryEscape转码的字符串还原。它会把%AB改为字节0xAB,将'+'改为' '。如果有某个%后面未跟两个十六进制数字,本函数会返回错误。
type Error
type Error struct {
Op string
URL string
Err error
}
Error会报告一个错误,以及导致该错误发生的URL和操作。
func (*Error) Error
func (e *Error) Error() string
type EscapeError
type EscapeError string
func (EscapeError) Error
func (e EscapeError) Error() string
type URL
type URL struct {
Scheme string
Opaque string // 编码后的不透明数据
User *Userinfo // 用户名和密码信息
Host string // host或host:port
Path string
RawQuery string // 编码后的查询字符串,没有'?'
Fragment string // 引用的片段(文档位置),没有'#'
}
URL类型代表一个解析后的URL(或者说,一个URL参照)。URL基本格式如下:
scheme://[userinfo@]host/path[?query][#fragment]
scheme后不是冒号加双斜线的URL被解释为如下格式:
scheme:opaque[?query][#fragment]
注意路径字段是以解码后的格式保存的,如/%47%6f%2f会变成/Go/。这导致我们无法确定Path字段中的斜线是来自原始URL还是解码前的%2f。除非一个客户端必须使用其他程序/函数来解析原始URL或者重构原始URL,这个区别并不重要。此时,HTTP服务端可以查询req.RequestURI,而HTTP客户端可以使用URL{Host: "example.com", Opaque: "//example.com/Go%2f"}代替{Host: "example.com", Path: "/Go/"}。
func Parse
func Parse(rawurl string) (url *URL, err error)
Parse函数解析rawurl为一个URL结构体,rawurl可以是绝对地址,也可以是相对地址。
func ParseRequestURI
func ParseRequestURI(rawurl string) (url *URL, err error)
ParseRequestURI函数解析rawurl为一个URL结构体,本函数会假设rawurl是在一个HTTP请求里,因此会假设该参数是一个绝对URL或者绝对路径,并会假设该URL没有#fragment后缀。(网页浏览器会在去掉该后缀后才将网址发送到网页服务器)
func (*URL) IsAbs
func (u *URL) IsAbs() bool
函数在URL是绝对URL时才返回真。
func (*URL) Query
func (u *URL) Query() Values
Query方法解析RawQuery字段并返回其表示的Values类型键值对。
func (*URL) RequestURI
func (u *URL) RequestURI() string
RequestURI方法返回编码好的path?query或opaque?query字符串,用在HTTP请求里。
func (*URL) String
func (u *URL) String() string
String将URL重构为一个合法URL字符串。
func (*URL) Parse
func (u *URL) Parse(ref string) (*URL, error)
Parse方法以u为上下文来解析一个URL,ref可以是绝对或相对URL。
本方法解析失败会返回nil, err;否则返回结果和ResolveReference一致。
func (*URL) ResolveReference
func (u *URL) ResolveReference(ref *URL) *URL
本方法根据一个绝对URI将一个URI补全为一个绝对URI,参见RFC 3986 节 5.2。参数ref可以是绝对URI或者相对URI。ResolveReference总是返回一个新的URL实例,即使该实例和u或者ref完全一样。如果ref是绝对URI,本方法会忽略参照URI并返回ref的一个拷贝。
type Userinfo
type Userinfo struct {
// 内含隐藏或非导出字段
}
Userinfo类型是一个URL的用户名和密码细节的一个不可修改的封装。一个真实存在的Userinfo值必须保证有用户名(但根据 RFC 2396可以是空字符串)以及一个可选的密码。
func User
func User(username string) *Userinfo
User函数返回一个用户名设置为username的不设置密码的*Userinfo。
func UserPassword
func UserPassword(username, password string) *Userinfo
UserPassword函数返回一个用户名设置为username、密码设置为password的*Userinfo。
这个函数应该只用于老式的站点,因为风险很大,不建议使用,参见RFC 2396。
func (*Userinfo) Username
func (u *Userinfo) Username() string
Username方法返回用户名。
func (*Userinfo) Password
func (u *Userinfo) Password() (string, bool)
如果设置了密码返回密码和真,否则会返回假。
func (*Userinfo) String
func (u *Userinfo) String() string
String方法返回编码后的用户信息,格式为"username[:password]"。
type Values
type Values map[string][]string
Values将建映射到值的列表。它一般用于查询的参数和表单的属性。不同于http.Header这个字典类型,Values的键是大小写敏感的。
func ParseQuery
func ParseQuery(query string) (m Values, err error)
ParseQuery函数解析一个URL编码的查询字符串,并返回可以表示该查询的Values类型的字典。本函数总是返回一个包含了所有合法查询参数的非nil字典,err用来描述解码时遇到的(如果有)第一个错误。
func (Values) Get
func (v Values) Get(key string) string
Get会获取key对应的值集的第一个值。如果没有对应key的值集会返回空字符串。获取值集请直接用map。
func (Values) Set
func (v Values) Set(key, value string)
Set方法将key对应的值集设为只有value,它会替换掉已有的值集。
func (Values) Add
func (v Values) Add(key, value string)
Add将value添加到key关联的值集里原有的值的后面。
func (Values) Del
func (v Values) Del(key string)
Del删除key关联的值集。
func (Values) Encode
func (v Values) Encode() string
Encode方法将v编码为url编码格式("bar=baz&foo=quux"),编码时会以键进行排序。