使用 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

客户端
客户端使用 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) // 并发处理连接
}
网友评论