美文网首页
golang ListenAndServe

golang ListenAndServe

作者: DifferentMan | 来源:发表于2023-06-15 16:56 被阅读0次
    // ListenAndServe listens on the TCP network address srv.Addr and then
    // calls Serve to handle requests on incoming connections.
    // Accepted connections are configured to enable TCP keep-alives.
    //
    // If srv.Addr is blank, ":http" is used.
    //
    // ListenAndServe always returns a non-nil error. After Shutdown or Close,
    // the returned error is ErrServerClosed.
    func (srv *Server) ListenAndServe() error {
        if srv.shuttingDown() {
            return ErrServerClosed
        }
        addr := srv.Addr
        if addr == "" {
            addr = ":http"
        }
        ln, err := net.Listen("tcp", addr)
        if err != nil {
            return err
        }
        return srv.Serve(ln)
    }
    
    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: fd, lc: sl.ListenConfig}, nil
    }
    
    func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string, ctrlFn func(string, string, syscall.RawConn) error) (fd *netFD, err error) {
        if (runtime.GOOS == "aix" || runtime.GOOS == "windows" || runtime.GOOS == "openbsd") && mode == "dial" && raddr.isWildcard() {
            raddr = raddr.toLocal(net)
        }
        family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
        return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn)
    }
    
    // socket returns a network file descriptor that is ready for
    // asynchronous I/O using the network poller.
    func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, ctrlFn func(string, string, syscall.RawConn) error) (fd *netFD, err error) {
        s, err := sysSocket(family, sotype, proto)
        if err != nil {
            return nil, err
        }
        if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
            poll.CloseFunc(s)
            return nil, err
        }
        if fd, err = newFD(s, family, sotype, net); err != nil {
            poll.CloseFunc(s)
            return nil, err
        }
    
        // This function makes a network file descriptor for the
        // following applications:
        //
        // - An endpoint holder that opens a passive stream
        //   connection, known as a stream listener
        //
        // - An endpoint holder that opens a destination-unspecific
        //   datagram connection, known as a datagram listener
        //
        // - An endpoint holder that opens an active stream or a
        //   destination-specific datagram connection, known as a
        //   dialer
        //
        // - An endpoint holder that opens the other connection, such
        //   as talking to the protocol stack inside the kernel
        //
        // For stream and datagram listeners, they will only require
        // named sockets, so we can assume that it's just a request
        // from stream or datagram listeners when laddr is not nil but
        // raddr is nil. Otherwise we assume it's just for dialers or
        // the other connection holders.
    
        if laddr != nil && raddr == nil {
            switch sotype {
            case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
                if err := fd.listenStream(laddr, listenerBacklog(), ctrlFn); err != nil {
                    fmt.Println("listenStream err========================",err)
                    fd.Close()
                    return nil, err
                }
                return fd, nil
            case syscall.SOCK_DGRAM:
                if err := fd.listenDatagram(laddr, ctrlFn); err != nil {
                    fd.Close()
                    return nil, err
                }
                return fd, nil
            }
        }
        if err := fd.dial(ctx, laddr, raddr, ctrlFn); err != nil {
            fd.Close()
            return nil, err
        }
        return fd, nil
    }
    
    func (fd *netFD) listenStream(laddr sockaddr, backlog int, ctrlFn func(string, string, syscall.RawConn) error) error {
        var err error
        if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
            return err
        }
        var lsa syscall.Sockaddr
        if lsa, err = laddr.sockaddr(fd.family); err != nil {
            return err
        }
        if ctrlFn != nil {
            c, err := newRawConn(fd)
            if err != nil {
                return err
            }
            if err := ctrlFn(fd.ctrlNetwork(), laddr.String(), c); err != nil {
                return err
            }
        }
        if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
            return os.NewSyscallError("bind", err)
        }
        if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
            return os.NewSyscallError("listen", err)
        }
        if err = fd.init(); err != nil {
            return err
        }
        lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
        fd.setAddr(fd.addrFunc()(lsa), nil)
        return nil
    }
    
    func Bind(fd int, sa Sockaddr) (err error) {
        ptr, n, err := sa.sockaddr()
        if err != nil {
            return err
        }
        return bind(fd, ptr, n)
    }
    
    // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
    
    func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
        _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
        if e1 != 0 {
            err = errnoErr(e1)
            //err = nil
        }
        return
    }
    

    这里err = nil,则服务不会报错,继续运行。
    在Linux x86_64架构中,系统调用号49对应于bind系统调用,这个调用用于将地址绑定到套接字。

    相关文章

      网友评论

          本文标题:golang ListenAndServe

          本文链接:https://www.haomeiwen.com/subject/guelydtx.html