使用 net 包构建时钟服务器。
时钟服务器
构建一个时钟服务器,每秒一次向客户端发送时间。
package main
import (
"io"
"log"
"net"
"time"
)
func main() {
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
continue
}
handleConn(conn)
}
}
func handleConn(conn net.Conn) {
defer conn.Close()
for {
_, err := io.WriteString(conn, time.Now().Format("2006-01-02 15:04:05\r\n"))
if err != nil {
return
}
time.Sleep(1 * time.Second)
}
}
Listen 函数创建一个 net.Listener 对象,它在一个网络端口上监听进来的连接,这里是 TCP 端口 localhost:8000。监听器的 Accept 方法被阻塞,知道有连接请求进来,然后返回 net.Conn 对象来代表一个连接。
handleConn 函数处理一个完整的客户端连接。在循环里,它将 time.Now() 获取的当前时间发送给客户端。因为 net.Conn 满足 io.Writer 接口,所以可以直接向它进行写入。当写入失败时循环结束,很多时候是客户端断开连接,这是 handleConn 函数使用延迟(defer)的 Close 调用关闭自己这边的连接,然后继续等待下一个连接请求。
使用 telnet 验证时钟服务器。
telnet lcoahost 8000
clock-server1.png
客户端
客户端使用 net.Dial 实现了 Go 版本的 netcat 程序,用来连接 TCP服务器。
package main
import (
"io"
"log"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
mustCopy(os.Stdout, conn)
}
func mustCopy(dst io.Writer, src io.Reader) {
if _, err := io.Copy(dst, src); err != nil {
log.Fatal(err)
}
}
支持并发的服务器
如果打开多个客户端,同时只有一个客户端能正常工作。第二个客户端必须等到第一个结束才能正常工作,这是因为服务器是顺序的,一次只能处理一个客户请求。让服务器支持并发需要在调用 handleConn 的地方添加一个 go 关键字,使它在自己的 goroutine 内执行。
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
continue
}
go handleConn(conn) // 并发处理连接
}
网友评论