Написать TCP прокси с golang, получить DATA RACE во время тестирования - PullRequest
0 голосов
/ 07 октября 2018

Я пытаюсь использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...