Я пытаюсь использовать golang для пересылки запроса на машину, которая не является общедоступной. Этот является полезным ответом.Однако, когда я запускаю тест для своего кода с --race
, он предупреждает DATA RACE , и тест не пройден.
Ниже приведен код.Гонка данных происходит в функции Response
proxy.go
, где вызываются два io.Copy
.И сообщение, созданное тестом, следующее:
Возможно ли разделить читателя и писателя соединения?Какой безопасный способ написания прокси?
Спасибо!
main.go
package main
import (
"fmt"
"io"
"net"
"net/http"
)
func server() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
})
http.ListenAndServe("127.0.0.1:80", nil)
}
func main() {
go server()
ln := NewServer("127.0.0.1", 8000)
if ln == nil {
fmt.Println("port not available")
} else {
for {
conn, err := ln.Accept()
if err != nil {
// handle error
}
go func() {
helloServer, err := net.Dial("tcp", "127.0.0.1:80")
if err != nil {
fmt.Println("Cannot connect to mock server!")
}
Response(conn, helloServer)
}()
}
}
}
proxy.go
package main
import (
"fmt"
"io"
"net"
"sync"
)
// NewServer create a socket listening on a given address
func NewServer(address string, port int) net.Listener {
ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", address, port))
if err != nil {
// handle error
ln = nil
}
return ln
}
// Response to the request of server
func Response(conn net.Conn, provider io.ReadWriter) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
io.Copy(conn, provider)
}()
io.Copy(provider, conn)
wg.Wait()
defer conn.Close()
}
proxy_test.go
package main
import (
"bufio"
"bytes"
"fmt"
"net"
"testing"
)
func GetServer(t *testing.T) (net.Listener, int) {
server, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Errorf("Cannot listen on any port")
}
port := server.Addr().(*net.TCPAddr).Port
return server, port
}
func TestResponse(t *testing.T) {
server, port := GetServer(t)
text := "Hello World\n"
go func(t *testing.T) {
for {
conn, err := server.Accept()
if err != nil {
// handle error
}
go Response(conn, bytes.NewBufferString(text))
}
}(t)
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
t.Errorf("Cannot connect to mock server!")
}
status, err := bufio.NewReader(conn).ReadString('\n')
if err != nil || status != text {
t.Errorf("Response method lost information! %s", status)
}
}
Ниже приведено сообщение
Выполнить go test --race
C:\Users\lenovo\go\src\github.com\limjcst\proxy>go test --race
==================
WARNING: DATA RACE
Write at 0x00c042126060 by goroutine 10:
bytes.(*Buffer).WriteTo()
C:/Go/src/bytes/buffer.go:238 +0x63
io.copyBuffer()
C:/Go/src/io/io.go:382 +0x49c
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:26 +0xe7
Previous write at 0x00c042126060 by goroutine 9:
bytes.(*Buffer).ReadFrom()
C:/Go/src/bytes/buffer.go:202 +0x50
io.copyBuffer()
C:/Go/src/io/io.go:386 +0x41e
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:28 +0x150
Goroutine 10 (running) created at:
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:24 +0xc8
Goroutine 9 (running) created at:
github.com/limjcst/proxy.TestResponse.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy_test.go:29 +0xb7
==================
==================
WARNING: DATA RACE
Read at 0x00c042126000 by goroutine 10:
bytes.(*Buffer).WriteTo()
C:/Go/src/bytes/buffer.go:74 +0x78
io.copyBuffer()
C:/Go/src/io/io.go:382 +0x49c
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:26 +0xe7
Previous write at 0x00c042126000 by goroutine 9:
bytes.(*Buffer).grow()
C:/Go/src/bytes/buffer.go:146 +0x23c
bytes.(*Buffer).ReadFrom()
C:/Go/src/bytes/buffer.go:204 +0x84
io.copyBuffer()
C:/Go/src/io/io.go:386 +0x41e
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:28 +0x150
Goroutine 10 (running) created at:
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:24 +0xc8
Goroutine 9 (running) created at:
github.com/limjcst/proxy.TestResponse.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy_test.go:29 +0xb7
==================
==================
WARNING: DATA RACE
Read at 0x00c042126018 by goroutine 10:
bytes.(*Buffer).WriteTo()
C:/Go/src/bytes/buffer.go:74 +0x9b
io.copyBuffer()
C:/Go/src/io/io.go:382 +0x49c
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:26 +0xe7
Previous write at 0x00c042126018 by goroutine 9:
bytes.(*Buffer).grow()
C:/Go/src/bytes/buffer.go:149 +0x27d
bytes.(*Buffer).ReadFrom()
C:/Go/src/bytes/buffer.go:204 +0x84
io.copyBuffer()
C:/Go/src/io/io.go:386 +0x41e
io.Copy()
C:/Go/src/io/io.go:362 +0x7b
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:28 +0x150
Goroutine 10 (running) created at:
github.com/limjcst/proxy.Response()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy.go:24 +0xc8
Goroutine 9 (running) created at:
github.com/limjcst/proxy.TestResponse.func1()
C:/Users/lenovo/go/src/github.com/limjcst/proxy/proxy_test.go:29 +0xb7
==================
--- FAIL: TestResponse (0.15s)
testing.go:730: race detected during execution of test
FAIL
exit status 1
FAIL github.com/limjcst/proxy 0.226s
Выполнить go env
C:\Users\lenovo\go\src\github.com\limjcst\proxy>go env
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\lenovo\AppData\Local\go-build
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\lenovo\go
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\lenovo\AppData\Local\Temp\go-build632729010=/tmp/go-build -gno-record-gcc-switches
Выполнить go version
C:\Users\lenovo\go\src\github.com\limjcst\proxy>go version
go version go1.10 windows/amd64