ListenAndServe源码剖析
程序员文章站
2022-04-14 18:58:25
使用goland追踪阅读ListenAndServe源码,剖析服务器启动流程 ListenAndServe阅读 ListenAndServe阅读 注意:创建一个server,启动server,我们也可以按照这2个步骤去创建一个web服务 Server结构阅读 Server结构阅读 注意:一般创建se ......
使用goland追踪阅读listenandserve源码,剖析服务器启动流程
-
listenandserve阅读
func listenandserve(addr string, handler handler) error {
//1. 创建server
server := &server{addr: addr, handler: handler}
//2. 启动server
return server.listenandserve()
}
注意:创建一个server,启动server,我们也可以按照这2个步骤去创建一个web服务
// 基类closer接口,关闭所有链接停止服务
type closer interface {
close() error
}
// 检查服务是否存活,里面定义了接口,接口的另类定义使用
// 奇怪的行为,不确定为什么这么做
func http2h1serverkeepalivesdisabled(hs *server) bool {
var x interface{} = hs
// 临时定义接口,使用【奇怪的使用方法】
type i interface {
dokeepalives() bool
}
if hs, ok := x.(i); ok {
return !hs.dokeepalives()
}
return false
}
//server
// a server defines parameters for running an http server.
// the zero value for server is a valid configuration.
type server struct {
addr string // 监听的tcp地址
handler handler // 注册的路由处理方法
// 如果服务需要支持https协议 那么需要相应的配置
tlsconfig *tls.config
//读超时设置
readtimeout time.duration
// 读取请求头超时设置
readheadertimeout time.duration
// 写超时
writetimeout time.duration
// 请求直接最长的空闲时长
idletimeout time.duration
// 请求头最大的容量
maxheaderbytes int
// https协议相关
tlsnextproto map[string]func(*server, *tls.conn, handler)
// 可以添回调函数,当客户端处于哪个状态时候可以执行某些动作
connstate func(net.conn, connstate)
// 错误日志器,不设置默认使用内置logger模块
errorlog *log.logger
//原子操作,是否保持长连接
disablekeepalives int32 // accessed atomically.
//原子操作,服务要关闭了
inshutdown int32 // accessed atomically (non-zero means we're in shutdown)
// https相关操作 用于初始化
nextprotoonce sync.once // guards setuphttp2_* init
nextprotoerr error // result of http2.configureserver if used
// 互斥锁 保证资源的安全
mu sync.mutex
// 服务套接字表,监听socket表
listeners map[*net.listener]struct{}
// 存活的客户端链接表
activeconn map[*conn]struct{}
//用于通知服务关闭了
donechan chan struct{}
// 注册服务器关闭执行的一些行为
onshutdown []func()
}
注意:一般创建server只需要addr与handler即可
-
listenandserve阅读
监听并启动服务
func (srv *server) listenandserve() error {
// 判断服务器是不是已经关闭了
if srv.shuttingdown() {
return errserverclosed
}
// 获取要绑定监听的地址
addr := srv.addr
if addr == "" {
addr = ":http"
}
// 创建用于监监听socket链接
ln, err := net.listen("tcp", addr)
if err != nil {
return err
}
// tcpkeepalivelistener 设置监听超时,在accept的时不会一直阻塞 设置一个超时操作
//启动服务
return srv.serve(tcpkeepalivelistener{ln.(*net.tcplistener)})
}
srv.serve源码阅读
func (srv *server) serve(l net.listener) error {
// 测试用的钩子函数,其他时候没有用的
if fn := testhookserverserve; fn != nil {
fn(srv, l) // call hook with unwrapped listener
}
// sync.once 创建一个once对象,用于防止多次关闭链接
l = &oncecloselistener{listener: l}
// 结束的时候关闭监听socket
defer l.close()
// 设置http2相关的设置
if err := srv.setuphttp2_serve(); err != nil {
return err
}
// 把监听socket添加监听表
if !srv.tracklistener(&l, true) {
return errserverclosed
}
// 结束的时候从监听表删除
defer srv.tracklistener(&l, false)
// 设置临时过期时间,当accept发生 错误的时候等待一段时间
var tempdelay time.duration // how long to sleep on accept failure
// 设置context 主要用于取消任务
basectx := context.background() // base is always background, per issue 16220
// 注意ctx把server本身传递进去了,用于传递
ctx := context.withvalue(basectx, servercontextkey, srv)
// 循环监听客户端到来
for {
// accept 阻塞等待客户单到来
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
tempdelay = 0
// 创建server连接,server连接包含了与客户端通讯的socket以及server相关的信息
c := srv.newconn(rw)
// 更新链接状态
c.setstate(c.rwc, statenew) // before serve can return
// 启动goroutine处理socket
go c.serve(ctx)
}
}
server conn结构体阅读
// 服务端链接结构体
type conn struct {
// 链接绑定服务
server *server
// 用于取消任务的ctxfunc
cancelctx context.cancelfunc
// socket 通讯用的底层socket
rwc net.conn
// 客户端地址127.0.0.0:5678
remoteaddr string
// tls 状态
tlsstate *tls.connectionstate
// werr is set to the first write error to rwc.
// 第一次写出现错误的时候设置
werr error
// r is bufr's read source.
// 用于读取请求的对象,主要用于读取数据的
r *connreader
// bufr reads from r.
// r读取的数据存储buf
bufr *bufio.reader
// bufw writes to checkconnerrorwriter{c}, which populates werr on error.
// 写buf
bufw *bufio.writer
// lastmethod is the method of the most recent request
// on this connection, if any.
// 最后一次请求,方法 是post还是其他等
lastmethod string
// 当前的请求
curreq atomic.value // of *response (which has a request in it)
// 当前cnn状态
curstate struct{ atomic uint64 } // packed (unixtime<<8|uint8(connstate))
//保护hijackedv
mu sync.mutex
// hijackedv is whether this connection has been hijacked
//表示是否支持用户劫持链接【主要用于切换协议的】
hijackedv bool
}
推荐阅读
-
HTML5实战与剖析之字符集属性(charset和defaultCharset)
-
HTML5实战与剖析之使用HTML5 WebSocket API
-
spring5 源码深度解析-----ApplicationContext容器refresh过程
-
Android开发中总结的Adapter工具类【附完整源码下载】
-
jQuery实现的响应鼠标移动方向插件用法示例【附源码下载】
-
netty源码解解析(4.0)-23 ByteBuf内存管理:分配和释放
-
前端Vue源码分析-逻辑层分析
-
并发编程之ThreadLocal源码分析
-
仿Aspnetpager的一个PHP分页类代码 附源码下载
-
利用纯CSS3实现动态的自行车特效源码