## 监听和服务
你可以启动服务器以侦听任何类型的 `net.Listener` 甚至 `http.Server` 实例。 服务器的初始化方法应在最后通过 `Run` 函数传递。
Go开发人员用来为其服务器提供服务的最常见方法是传递一个以“ hostname:ip”形式出现的网络地址。对于Iris,我们使用 `iris.Addr`,它是一个 `iris.Runner` 类型。
```
// 侦听网络地址为 0.0.0.0:8080 的 tcp 协议
app.Run(iris.Addr(":8080"))
```
有时候你已经在应用程序中创建了标准的 net/http 服务,并希望使用该服务器为 Iris Web 应用程序提供服务。
```
// 与前面相同,但使用的自定义 http.Server 也可能在其他地方使用
app.Run(iris.Server(&http.Server{Addr:":8080"}))
```
最高级的用法是创建自定义或标准 `net.Listener` 并将其传递给 `app.Run`。
```
// 用自定义的 net.Listener
l, err := net.Listen("tcp4", ":8080")
if err != nil {
panic(err)
}
app.Run(iris.Listener(l))
```
一个更完整的示例,使用 unix-only socket 文件功能。
```
package main
import (
"os"
"net"
"github.com/kataras/iris/v12"
)
func main() {
app := iris.New()
// UNIX socket
if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) {
app.Logger().Fatal(errOs)
}
l, err := net.Listen("unix", socketFile)
if err != nil {
app.Logger().Fatal(err)
}
if err = os.Chmod(socketFile, mode); err != nil {
app.Logger().Fatal(err)
}
app.Run(iris.Listener(l))
}
```
UNIX 和 BSD hosts 可以利用重用端口功能
```
package main
import (
// tcplisten 包提供可自定义的 TCP net.Listener , 其中包含各种
// 与性能相关的选项:
//
// - SO_REUSEPORT.。 此选项允许线性扩展服务器性能
// 在多CPU服务器上。
// 有关详细信息,请参见 https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ 。
//
// - TCP_DEFER_ACCEPT。 此选项希望服务器从接受的文件中读取
// 在写入之前先进行连接。
//
// - TCP_FASTOPEN.。 有关详细信息,请参见 https://lwn.net/Articles/508865/ for details 。
"github.com/valyala/tcplisten"
"github.com/kataras/iris/v12"
)
// go get github.com/valyala/tcplisten
// go run main.go
func main() {
app := iris.New()
app.Get("/", func(ctx iris.Context) {
ctx.HTML("<h1>Hello World!</h1>")
})
listenerCfg := tcplisten.Config{
ReusePort: true,
DeferAccept: true,
FastOpen: true,
}
l, err := listenerCfg.NewListener("tcp", ":8080")
if err != nil {
app.Logger().Fatal(err)
}
app.Run(iris.Listener(l))
}
```
### [HTTP/2 和安全](https://github.com/kataras/iris/wiki/Host#http2-and-secure)
如果你已签名文件密钥,则可以基于这些证书密钥使用 `iris.TLS` 服务 `https` 。
```
// TLS 使用密钥文件
app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key"))
```
当应用准备好 [生产] 时,应该使用的方法是 `iris.AutoTLS` 启动安全服务器。 由 [https://letsencrypt.org](https://letsencrypt.org/) **免费** 提供。
```
// 自动 TLS
app.Run(iris.AutoTLS(":443", "example.com", "admin@example.com"))
```
### [Any `iris.Runner`](https://github.com/kataras/iris/wiki/Host#any-irisrunner)
有时候可能希望聆听非常特殊的内容,而不是 `net.Listener` 类型。可以通过 `iris.Raw` 来做到这一点,但是你要对这种方法负责
```
// 使用任何 func() 错误,
// 启动倾听者的责任由你这样决定,
// 为了简单起见,我们将使用
// "net/http" 包的 ListenAndServe 方法。
srv := &http.Server{Addr:":8080"}
app.Run(iris.Raw(srv.ListenAndServe))
```
## [Host 配置](https://github.com/kataras/iris/wiki/Host#host-configurators)
以上所有形式的监听都接受 `func(* iris.Supervisor)` 的最后一个可变参数。这个参数用于给通过这些方法传递的特定主机添加配置。
例如,假设我们要添加一个在服务器关闭时触发的回调
```
app.Run(iris.Addr(":8080", func(h *iris.Supervisor) {
h.RegisterOnShutdown(func() {
println("server terminated")
})
}))
```
甚至可以在 `app.Run` 方法之前执行此操作,但区别在于这些 host 配置程序将被执行到可用于为Web应用提供服务的所有 host (通过 `app.NewHost` 一会儿我们就可以看到)
```
app := iris.New()
app.ConfigureHost(func(h *iris.Supervisor) {
h.RegisterOnShutdown(func() {
println("server terminated")
})
})
app.Run(iris.Addr(":8080"))
```
在`Run`方法之后,可以通过 `Application#Hosts` 字段设置应用程序提供服务的所有 host 的访问权限。
但是最常见的情况是,你可能需要在 `app.Run` 方法之前访问 host,有两种方法可以访问 host 管理器,请参见下文。
我们已经了解了如何通过 `app.Run` 或 `app.ConfigureHost` 的第二个参数配置所有应用程序的 host 。还有一种更适合简单场景的方法,即使用 `app.NewHost` 创建新 host 并使用它的 `Serve` 或者 `Listen` 方法通过 `iris#Raw` Runner 启功应用程序。
请注意,这种方式需要额外引入 `net/http` 包。
示例代码:
```
h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
println("server terminated")
})
app.Run(iris.Raw(h.ListenAndServe))
```
## [多 hosts](https://github.com/kataras/iris/wiki/Host#multi-hosts)
你可以使用多个服务器来服务 Iris Web 应用, `iris.Router` 与 `net/http/Handler` 方法兼容。因此 ,如你所知道的那样, 它可用于在任何`net / http` 服务器上进行改造,但是有一种更简单的方法,使用 `app.NewHost`复制所有 host 配置程序并通过 `app.Shutdown` 关闭所有连接到特定 Web 应用程序的 host 。
```
app := iris.New()
app.Get("/", indexHandler)
// 以不同的 goroutine 运行,来防止主 "goroutine" 不被干扰。
go app.Run(iris.Addr(":8080"))
// 启动第二台正在监听 tcp 0.0.0.0:9090 的服务器,
// 不带 "go" 关键字,因为我们要在上次服务器运行时阻塞。
app.NewHost(&http.Server{Addr:":9090"}).ListenAndServe()
```
## [关机 (正常)](https://github.com/kataras/iris/wiki/Host#shutdown-gracefully)
让我们继续学习如何捕获 CONTROL+C/COMMAND+C 或者 unix kill 命令并正常关闭服务器。
> 通过 CONTROL+C/COMMAND+C 正常关机或者当 kill 命令被设置为 ENABLED BY-DEFAULT 的时候。
为了手动管理应用中断时要执行的操作,我们需要通过 `WithoutInterruptHandler` 禁用默认行为并注册一个新的中断处理程序 (全局的, 在所有可用 hosts 上的)。
示例代码:
```
package main
import (
"context"
"time"
"github.com/kataras/iris/v12"
)
func main() {
app := iris.New()
iris.RegisterOnInterrupt(func() {
timeout := 5 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// 关闭所有 hosts
app.Shutdown(ctx)
})
app.Get("/", func(ctx iris.Context) {
ctx.HTML(" <h1>hi, I just exist in order to see if the server is closed</h1>")
})
app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)
}
```
继续阅读 [配置](https://github.com/kataras/iris/wiki/Configuration) 章节, 以了解`app.Run` 的第二个可变参数。
