简体   繁体   中英

How to cache a TCP reverse proxy data transmission?

I've accomplished implementing TCP reverse proxy in GoLang. But unfortunately couldn't come up with implementing caching to a TCP reverse proxy. Is it possible to do so, if yes, is there any resource out there? Is caching possible on a TCP (Transport Layer of Network)?

Here's the simple TCP reverse proxy in Golang.

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
        }
    }
}

You are asking how to save data read from an io.Reader. That's different from caching.

The easiest approach is to tee the reader into a buffer .

While you are at it, you might as well use io.Copy instead of the similar code in the question. The code in the question does not handle the case when read returns n > 0 and a non-nil error.

Use an error group to coordinate waiting for the goroutines and collecting error status.

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.

The name of the programming language is "Go", not "Golang" or "GoLang".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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