net包 listen - golang
在前面我们简单的了解了一下,如何构建客户端请求,同时简单的了解了他们之间的调用和封装关系。从而在封装方法在满足不了需求时,我们可以使用更底层一级的方法构建自己的需求。
今天我们看一下服务端的一些监听方法,在go中监听方法大致有
http.ListenAndServeTLS()
http.ListenAndServe()
net.Listen()
net.ListenPacket()
net.ListenTcp()
net.ListenUnix()
net.ListenUdp()
net.ListenIp()
net.ListenUnixgram()
net.ListenMulticastUDP()
让我们通过一张图来看看他们之间的关系:
由图可以看出,http的监听是对net.Listen()的封装,而net.Listen()是对Tcp和Unix的封装。而http的监听传入的都是tcp。所有http的监听最终都是实现的net.ListenTcp()。
其中 net.ListenTcp,net.ListenUdp(),net.ListenIP() 最终走的都是 internetSocket ()。
下面先让我们看一段代码:
func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", sl.ListenConfig.Control)
if err != nil {
return nil, err
}
return &TCPListener{fd}, nil
}
func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)
for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
if err == nil {
fd.Close()
}
fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)
}
if err != nil {
return nil, err
}
return newTCPConn(fd), nil
}
通过代码对比,调用internetSocket只是传入了不同的识别符 dial和listen 。同时tcp的dial和listen在逻辑上也有些不同,但是如果你去看udp的dial和listen会发现他们的逻辑完全一样。
说了这么多废话后,让我们看看如何实现一个服务端,首先是我们最常用的http服务:
http.ListenAndServe(),go的web服务构建很简单只需要构建监听路由,然后调用监听传入端口就可以了 :
http.HandleFunc("/", HelloServer)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
http.ListenAndServeTLS和ListenAndServe基本相同,只是需要多传入2个钥匙:
http.HandleFunc("/", handler)
http.ListenAndServeTLS(":8081", "server.crt",
"server.key", nil)
对于net.Listen处理起来就要比http的麻烦点,他需要你手动处理客户端请求和实现服务:
func chkError(err error) {
if err != nil {
log.Fatal(err);
}
}
//单独处理客户端的请求
func clientHandle(conn net.Conn) {
defer conn.Close();
conn.Write([]byte("hello " + time.Now().String()));
}
func main() {
//创建一个TCP服务端
tcpaddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:8080");
chkError(err);
//监听端口
tcplisten, err2 := net.ListenTCP("tcp", tcpaddr);
chkError(err2);
//死循环的处理客户端请求
for {
//等待客户的连接
conn, err3 := tcplisten.Accept();
//如果有错误直接跳过
if err3 != nil {
continue;
}
//通过goroutine来处理用户的请求
go clientHandle(conn);
}
}