美文网首页
go如何使用sendfile/splice

go如何使用sendfile/splice

作者: wwq2020 | 来源:发表于2024-10-08 16:11 被阅读0次

如何使用sendfile/splice

tcpserver

io.Copy(clientConn, backendConn)

httpserver

io.Copy(w, yourfile)

相关源码

sendFile/splice

net/splice_linux.go中

func splice(c *netFD, r io.Reader) (written int64, err error, handled bool) {
    var remain int64 = 1<<63 - 1 // by default, copy until EOF
    lr, ok := r.(*io.LimitedReader)
    if ok {
        remain, r = lr.N, lr.R
        if remain <= 0 {
            return 0, nil, true
        }
    }

    var s *netFD
    if tc, ok := r.(*TCPConn); ok {
        s = tc.fd
    } else if uc, ok := r.(*UnixConn); ok {
        if uc.fd.net != "unix" {
            return 0, nil, false
        }
        s = uc.fd
    } else {
        return 0, nil, false
    }

    written, handled, sc, err := poll.Splice(&c.pfd, &s.pfd, remain)
    if lr != nil {
        lr.N -= written
    }
    return written, wrapSyscallError(sc, err), handled
}

net/sendfile_linux.go中

func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
    var remain int64 = 1<<63 - 1 // by default, copy until EOF

    lr, ok := r.(*io.LimitedReader)
    if ok {
        remain, r = lr.N, lr.R
        if remain <= 0 {
            return 0, nil, true
        }
    }
    f, ok := r.(*os.File)
    if !ok {
        return 0, nil, false
    }

    sc, err := f.SyscallConn()
    if err != nil {
        return 0, nil, false
    }

    var werr error
    err = sc.Read(func(fd uintptr) bool {
        written, werr, handled = poll.SendFile(&c.pfd, int(fd), remain)
        return true
    })
    if err == nil {
        err = werr
    }

    if lr != nil {
        lr.N = remain - written
    }
    return written, wrapSyscallError("sendfile", err), handled
}

tcpconn

tcpconn都实现了ReadFrom,而其中使用了sendfile/splice

net/tcpsock.go中

func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
    if !c.ok() {
        return 0, syscall.EINVAL
    }
    n, err := c.readFrom(r)
    if err != nil && err != io.EOF {
        err = &OpError{Op: "readfrom", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    }
    return n, err
}

net/tcpsock_posix.go中

func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
    // 针对r是tcpconn或者unixconn
    if n, err, handled := splice(c.fd, r); handled {
        return n, err
    }
    //针对r是*os.File或者*io.LimitedReader包装过的*os.File
    if n, err, handled := sendFile(c.fd, r); handled {
        return n, err
    }
    // 其他
    return genericReadFrom(c, r)
}

io.Copy

func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
    written, err = Copy(dst, LimitReader(src, n))
    if written == n {
        return n, nil
    }
    ...
}

func Copy(dst Writer, src Reader) (written int64, err error) {
    return copyBuffer(dst, src, nil)
}

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
    ...
    return copyBuffer(dst, src, buf)
}

func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
    ...
    if rt, ok := dst.(ReaderFrom); ok {
        return rt.ReadFrom(src)
    }
    ...
}

相关文章

网友评论

      本文标题:go如何使用sendfile/splice

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