Hello,
I have a function to read from a connection and do some data processing and then write to another connection, the following are 2 different approaches. Here's the first approach without channel and go routines:
func (p *Proxy) pipe(from io.Reader, to io.Writer, dataHandler func(input []byte) ([]byte, error)) {
defer p.cancelGlobal()
for {
select {
case <-p.ProxyCtx.Done():
return
default:
}
buf := make([]byte, 4096)
n, err := from.Read(buf)
if err != nil {
return
}
var pktout []byte
if dataHandler != nil {
pktout, err = dataHandler(buf[0:n])
if err != nil {
p.log.Error("processing data error: ", err.Error(), ", ignoring...")
continue
}
} else {
pktout = buf[0:n]
}
if pktout != nil && len(pktout) > 0 {
if _, err = to.Write(pktout); err != nil {
p.log.Error(err.Error())
}
}
}
}
Here's the second approach which has a channel and a new Go routine:
func (p *Proxy) pipe(from io.Reader, to io.Writer, dataHandler func(input []byte) ([]byte, error)) {
defer p.cancelGlobal()
out := make(chan []byte)
go func() {
LOOP:
for {
select {
case <-p.ProxyCtx.Done():
break LOOP
case data := <-out:
var pktout []byte
var err error
if dataHandler != nil {
pktout, err = dataHandler(data)
if err != nil {
p.log.Error("processing data error: ", err.Error(), ", ignoring...")
continue
}
} else {
pktout = data
}
if pktout != nil && len(pktout) > 0 {
if _, err := to.Write(pktout); err != nil {
p.log.Error(err.Error())
}
}
}
}
}()
for {
select {
case <-p.ProxyCtx.Done():
return
default:
}
buf := make([]byte, 4096)
n, err := from.Read(buf)
if err != nil {
return
}
out <- buf[0:n]
}
}
What are the main differences between the 2 approches above and which one is better? To me I think the first one is simpler. But what is the value of adding a channel in the 2nd approach?
Thanks,
Bin