服务端
服务端是用来接收连接的,因此需要一个监听的逻辑
// 函数ListenAndServe用来开启服务并且监听,而这个
// 函数的核心就是tcp连接,通过net.Listen(param1,param2)得到listener
// 其中param1是连接类型,可以有tcp,tcp4,tcp6......,param2则是服务地址:ip:port
// 返回的listener是一个interface{}类型
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
}
只要实现了Listener的三个函数的结构体,都能作为返回参数,以param1=tcp为例子,将会返回TCPListener
// TCPListener is a TCP network listener. Clients should typically
// use variables of type Listener instead of assuming TCP.
type TCPListener struct {
fd *netFD
}
// Network file descriptor.
type netFD struct {
pfd poll.FD
// immutable until Close
family int
sotype int
isConnected bool // handshake completed or use of association with peer
net string
laddr Addr
raddr Addr
}
// family 地址系列、地址族
AF_UNSPEC = 0
AF_UNIX = 1
AF_INET = 2
AF_INET6 = 23
AF_NETBIOS = 17
// sotype 套接字类型
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
SOCK_SEQPACKET = 5
// net 连接类型
// laddr localaddress本地地址
// raddr remoteaddress远程地址
// 通过newFD函数返回TCPListenner的需要的子结构fd
func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
ret := &netFD{
pfd: poll.FD{
Sysfd: sysfd,
IsStream: sotype == syscall.SOCK_STREAM,
ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
},
family: family,
sotype: sotype,
net: net,
}
return ret, nil
}
// laddr与raddr在listenstream中set进去
func (fd *netFD) listenStream(laddr sockaddr, backlog int, ctrlFn func(string, string, syscall.RawConn) error) error {
var err error
if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
return err
}
var lsa syscall.Sockaddr
if lsa, err = laddr.sockaddr(fd.family); err != nil {
return err
}
if ctrlFn != nil {
c, err := newRawConn(fd)
if err != nil {
return err
}
if err := ctrlFn(fd.ctrlNetwork(), laddr.String(), c); err != nil {
return err
}
}
if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
return os.NewSyscallError("bind", err)
}
if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
return os.NewSyscallError("listen", err)
}
if err = fd.init(); err != nil {
return err
}
lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
fd.setAddr(fd.addrFunc()(lsa), nil)
return nil
}
func (fd *netFD) setAddr(laddr, raddr Addr) {
fd.laddr = laddr
fd.raddr = raddr
runtime.SetFinalizer(fd, (*netFD).Close)
}
通过以上操作将会得到一个参数齐全的tcpListener,并且以listener接口类型返回给使用者, 这里值得提的是代码中三个实现的函数并不都是用tcpListener的实现 其中Addr()函数用的是tcpListener的具体实现 Accept()用的是tcpKeepAliveListener的具体实现 Close()用的是onceCloseListener的具体实现 tcpKeepAliveListener是通过将tcplistener作为自己的子结构,再次实现Accept函数 onceCloseListener是通过将tcpKeepAliveListener作为自己的子结构,再次实现Close函数
type tcpKeepAliveListener struct {
*net.TCPListener
}
func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
tc, err := ln.AcceptTCP()
if err != nil {
return nil, err
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}
// AcceptTCP accepts the next incoming call and returns the new
// connection.
func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
if !l.ok() {
return nil, syscall.EINVAL
}
c, err := l.accept()
if err != nil {
return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
}
return c, nil
}
// onceCloseListener wraps a net.Listener, protecting it from
// multiple Close calls.
type onceCloseListener struct {
net.Listener
once sync.Once
closeErr error
}
func (oc *onceCloseListener) Close() error {
oc.once.Do(oc.close)
return oc.closeErr
}
func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() }
最后实际建立连接的函数,调用的还是netFD的accept(),通过将连接建立成功的local与remote地址存放在netFD中关联起来
func (fd *netFD) accept() (*netFD, error) {
s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
return sysSocket(fd.family, fd.sotype, 0)
})
if err != nil {
if errcall != "" {
err = wrapSyscallError(errcall, err)
}
return nil, err
}
// Associate our new socket with IOCP.
netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
if err != nil {
poll.CloseFunc(s)
return nil, err
}
if err := netfd.init(); err != nil {
fd.Close()
return nil, err
}
// Get local and peer addr out of AcceptEx buffer.
var lrsa, rrsa *syscall.RawSockaddrAny
var llen, rlen int32
syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr()
netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
return netfd, nil
}
具体的accept函数逻辑暂时不去分析,当前只用知道创建监听者成功后, 通过accept函数可以获取远程连接,且将远程连接与本地连接关联起来返回给使用者
注册handle
这里将handle理解为路由,通过函数调用将路由与对应的处理函数以key value的形式存储起来
http.Handle("/hello2", &hello{})
http.Handle("/hello", http.HandlerFunc(Hello))
// 这里实现的函数或者结构体也好,都要实现Handler接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// 注册成功的handle都会存在DefaultServeMux中
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
调用handle
在accept连接成功后,会单开一个协程为连接服务
for {
rw, e := l.Accept()
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
在serve函数中会先做一些细节处理,然后读取请求,具体什么不去分析,处理结束后, 读取http客户端请求成功后,会对DefaultServeMux轮询,找到合适的路由,并执行对应路由函数的相关逻辑
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req)
w.cancelCtx()
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
以上就是golang自带http服务的基本内容,包括了服务器的启动,监听者Listener的具体结构分析、路由的注册、handle的储存方式、以及handle的调用
稍后会继续分析accept接收成功后的conn对象具体结构,以及读写操作的实现函数分析