繁体   English   中英

如何缓存一个TCP反向代理数据传输?

[英]How to cache a TCP reverse proxy data transmission?

我已经在 GoLang 中实现了 TCP 反向代理。 但不幸的是,无法为 TCP 反向代理实现缓存。 是否可以这样做,如果可以,是否有任何资源? 是否可以在 TCP(网络传输层)上进行缓存?

这是Golang中简单的TCP反向代理。

package main

import (
    "io"
    "log"
    "net"
)

//Proxy struct
type Proxy struct {
    laddr, raddr *net.TCPAddr
    lconn, rconn io.ReadWriteCloser
    errorSignal  chan bool
}

// New Create a new Proxy instance.
func New(lconn *net.TCPConn, laddr, raddr *net.TCPAddr) *Proxy {
    return &Proxy{
        lconn:       lconn,
        laddr:       laddr,
        raddr:       raddr,
        errorSignal: make(chan bool),
    }
}

//TCPAddressResolver resolves an address and returns to a struct having ip and port.
func TCPAddressResolver(addr string) (tcpAddress *net.TCPAddr, err error) {
    tcpAddress, err = net.ResolveTCPAddr("tcp", addr)
    return
}
func main() {
    listenerAddress, err := TCPAddressResolver(":8080")
    if err != nil {
        log.Fatalf("Failed to resolve local address: %v", err)
    }

    remoteAddress, err := TCPAddressResolver(":3000")

    if err != nil {
        log.Fatalf("Failed to resolve remote address: %v", err)
    }

    listener, err := net.ListenTCP("tcp", listenerAddress)

    if err != nil {
        log.Fatalf("Failed to open local port to listen: %v", err)
    }

    log.Printf("Simple Proxy started on: %d and forwards to port %d", listenerAddress.Port, remoteAddress.Port)

    for {
        conn, err := listener.AcceptTCP()

        if err != nil {
            log.Fatalf("Failed to accept connection: %v", err)
            continue
        }

        var p *Proxy
        // HTTP is a stateless protocol thus a proxy needs to reinitiate the new next incoming call (conn)
        // each time it finishes handling the previous one.
        p = New(conn, listenerAddress, remoteAddress)
        p.Start()
    }
}

//Start initiates transmission of data to and from the remote to client side.
func (p *Proxy) Start() {
    defer p.lconn.Close()

    var err error

    p.rconn, err = net.DialTCP("tcp", nil, p.raddr)

    if err != nil {
        log.Fatalf("Remote connection failure: %v", err)
    }

    defer p.rconn.Close()

    go p.CopySrcDst(p.lconn, p.rconn)
    go p.CopySrcDst(p.rconn, p.lconn)

    //Wait for everything to close -- This one blocks the routine.
    <-p.errorSignal
    log.Printf("Closing Start routine \n")
}

func (p *Proxy) err(err error) {
    if err != io.EOF {
        log.Printf("Warning: %v: Setting error signal to true", err)
    }
    p.errorSignal <- true
}

//CopySrcDst copies data from src to dest
func (p *Proxy) CopySrcDst(src, dst io.ReadWriteCloser) {
    buff := make([]byte, 1024)
    for {
        n, err := src.Read(buff)
        if err != nil {
            // Reading error.
            p.err(err)
            return
        }

        dataFromBuffer := buff[:n]

        n, err = dst.Write(dataFromBuffer)
        if err != nil {
            // Writing error.
            p.err(err)
            return
        }
    }
}

您正在询问如何保存从 io.Reader 读取的数据。 这与缓存不同。

最简单的方法是将阅读器放入缓冲区

当您使用它时,您不妨使用io.Copy而不是问题中的类似代码。 问题中的代码不处理 read 返回 n > 0 和非零错误的情况。

使用错误组来协调等待 goroutine 和收集错误状态。

var g errgroup.Group
var rbuf, lbuf bytes.Buffer

g.Go(func() error {
    _, err := io.Copy(lconn, io.TeeReader(p.rconn, &rbuf))
    return err
})
g.Go(func() error {
    _, err := io.Copy(rconn, io.TeeReader(p.lconn, &lbuf))
    return err
})
if err := g.Wait(); err != nil {
    // handle error
}
// rbuf and lbuf have the contents of the two streams.

编程语言的名称是“Go”,而不是“Golang”或“GoLang”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM