英文:
GoLang(cgp) http.Client get request hangs from Linux daemon process
问题
我已经写了一个简单的GoLang函数,它使用http.Client进行HTTP GET请求并打印响应字符串。然后,我使用以下命令将其导出为.so文件中的C函数。
go build -o libapp.so -buildmode=c-shared libapp.go
然后,使用这个.SO文件和.h文件,从我的C测试程序中调用导出的Go函数。以下是我用于编译和构建C测试程序的命令。
gcc -o goclient goclient.c ./libapp.so
这是GoLang中的CheckConnection函数:
var file io.Writer
//export CheckConnection
func CheckConnection() {
path := "/opt/logs/gologs.txt"
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
file = f
log.SetOutput(file)
log.Print("---------Logging started---------")
log.Print("Hello from CheckConnection\r\n")
log.Print("CheckConnection creating http.Client: step1")
var netTransport = &http.Transport{
Dial: (&net.Dialer{
Timeout: 10 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
}
log.Print("CheckConnection creating http.Client: step2")
var myClient = &http.Client{
Timeout: time.Second * 10,
Transport: netTransport,
}
log.Print("CheckConnection creating http.Client: step3")
res,err := myClient.Get("https://www.google.com")
log.Print("CheckConnection creating http.Client: step4")
if err!= nil {
log.Print("Error ",err)
}
log.Print("CheckConnection creating http.Client: step5")
data,_ := ioutil.ReadAll(res.Body)
log.Print("CheckConnection creating http.Client: step6")
res.Body.Close()
log.Print("CheckConnection creating http.Client: step7")
log.Print("Resp code ",res.StatusCode)
log.Print("Data ",data)
defer log.Print("Returning from CheckConnection");
}
线程在下面的代码行处被阻塞,不会超时或报错:
res,err := myClient.Get("https://www.google.com")
当从守护进程调用CheckConnection()函数时会发生这种情况。如果我从C、C++的main()进程中调用这个函数,它就能正常工作。我在GitHub上报告了同样的问题https://github.com/golang/go/issues/47077。它有一个可以重现该问题的示例代码(Sample.zip)。
请参考GitHub问题https://github.com/golang/go/issues/47077,获取可重现问题的示例代码。
以下是go env的内容:
GO111MODULE=""
GOARCH="386"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="386"
GOHOSTOS="linux"
GOINSECURE="golang.org,googlesource.com"
GOMODCACHE="/home/nilesh/golang/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/nilesh/golang"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_386"
GOVCS=""
GOVERSION="go1.16.4"
GCCGO="gccgo"
GO386="sse2"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/nilesh/SVN/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m32 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build718813889=/tmp/go-build -gno-record-gcc-switches"
英文:
I have written a simple GoLang function which makes HTTP GET request using http.Client and prints the response string. I then exported it as C function in .so file using following command.
go build -o libapp.so -buildmode=c-shared libapp.go
Then using this .SO and .h, called exported Go function from my C test program. Below is the command I used to compile and build my C test program.
gcc -o goclient goclient.c ./libapp.so
Here is CheckConnection function in GoLang
var file io.Writer
//export CheckConnection
func CheckConnection() {
path := "/opt/logs/gologs.txt"
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
file = f
log.SetOutput(file)
log.Print("---------Logging started---------")
log.Print("Hello from CheckConnection\r\n")
log.Print("CheckConnection creating http.Client: step1")
var netTransport = &http.Transport{
Dial: (&net.Dialer{
Timeout: 10 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
}
log.Print("CheckConnection creating http.Client: step2")
var myClient = &http.Client{
Timeout: time.Second * 10,
Transport: netTransport,
}
log.Print("CheckConnection creating http.Client: step3")
res,err := myClient.Get("https://www.google.com")
log.Print("CheckConnection creating http.Client: step4")
if err!= nil {
log.Print("Error ",err)
}
log.Print("CheckConnection creating http.Client: step5")
data,_ := ioutil.ReadAll(res.Body)
log.Print("CheckConnection creating http.Client: step6")
res.Body.Close()
log.Print("CheckConnection creating http.Client: step7")
log.Print("Resp code ",res.StatusCode)
log.Print("Data ",data)
defer log.Print("Returning from CheckConnection");
}
Thread gets blocked at below line, does not timeout or gives error -
res,err := myClient.Get("https://www.google.com")
This happens when CheckConnection() function gets called from Daemon process. If I call this function from C,C++ main() process then it works. I have reported same issue on GitHub https://github.com/golang/go/issues/47077. It has sample code to reproduce the issue (Sample.zip).
Please refer to GitHub issue https://github.com/golang/go/issues/47077 for sample reproducible code.
Adding go env below
GO111MODULE=""
GOARCH="386"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="386"
GOHOSTOS="linux"
GOINSECURE="golang.org,googlesource.com"
GOMODCACHE="/home/nilesh/golang/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/nilesh/golang"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_386"
GOVCS=""
GOVERSION="go1.16.4"
GCCGO="gccgo"
GO386="sse2"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/nilesh/SVN/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m32 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build718813889=/tmp/go-build -gno-record-gcc-switches"
答案1
得分: 0
默认情况下,DefaultClient没有超时设置。你可以尝试使用自己的客户端并设置超时时间。
var myClient = &http.Client{
Timeout: time.Second * 10,
}
英文:
By default there is no timeout for the DefaultClient. Could you try with own client with timeout set up?
var myClient = &http.Client{
Timeout: time.Second * 10,
}
答案2
得分: 0
在Linux上使用cgp共享库时,如果你从forked进程中调用这些函数,请确保考虑以下几点:
-
不要静态链接共享库,而是使用dlopen、dlsym、dlclose动态加载它。
-
确保在上述过程中不要在链接时提供共享库名称。
这解决了我的问题,我能够从我的forked进程中进行网络调用。
英文:
When using cgp shared library in your C/C++ program on linux and if you are calling these functions from forked process then make sure you should consider below points.
-
Do not statically link the shared library, instead load it dynamically using dlopen, dlsym, dlclose.
-
Make sure while doing above you are not providing shared lib name during linking
This solved my problem and I am able to to make network calls from my forked process.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论