所以,我试图在没有忙碌等待的情况下从stdin读取,忽略EOF,因为我的情况下的客户端会来来去去。在C中我会使用一个简单的select()或poll(),但我正在尝试学习Go,而我对于缺少select()或poll()感到非常沮丧。我在Go中找不到使用select和channel的好方法,因为Read()将立即返回EOF并且我回到忙碌的等待状态。 syscall.Select()似乎是最好的方法,但Go并没有费心去实现FD_SET! 叹息
所以,我正在尝试使用cgo。
package main
/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
FD_SET(sysfd, (fd_set*)set);
}
*/
import "C"
import (
"unsafe"
但是当我尝试在我的Mac上构建它时,我得到了这个。
# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET
clang errors for preamble:
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected identifier or '('
void _FD_SET(int sysfd, void *set) {
^
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected ')'
src/github.com/msoulier/mlogd/mlogd.go:6:13: note: to match this '('
void _FD_SET(int sysfd, void *set) {
^
2 errors generated.
如果我将导入合并在一起,那么大多数错误就会消失。
package main
/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
FD_SET(sysfd, (fd_set*)set);
}
*/
import (
"C"
"unsafe"
"syscall"
但还有一个。
# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET
所以,我在这里寻找两件事。
我的环境。
msoulier@merlin:~/work/go$ go version
go version go1.6.2 darwin/amd64
msoulier@merlin:~/work/go$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/msoulier/work/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.6.2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.6.2/libexec/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
提前致谢。必须比这更简单。
我选择了这一点。
// loop forever - we expect to be killed with a SIGTERM or SIGINT
for {
logger.Debug("going into select on stdin")
var r_fdset syscall.FdSet
for i := 0; i < 16; i++ {
r_fdset.Bits[i] = 0
}
r_fdset.Bits[0] = 1
selerr := syscall.Select(1, &r_fdset, nil, nil, nil)
if selerr != nil {
logger.Warning(selerr)
}
但即使输入用完,它也会立即返回。
麦克
答案 0 :(得分:1)
在Go中,您可以执行阻止操作。无处不在。
你把那些阻塞操作放在goroutine中,就像绿色线程/光纤一样。它们由Go运行时调度,可能位于实际线程上,也可能是共享线程。
然后你使用频道与你Go计划的其他部分交谈。
对于你的问题,在EOF之后,stdin总是可读的,只是停止阅读它。我的读者goroutine就在下面退出。
在这里,有一个我刚才写的样本:
package main
import (
"fmt"
"io"
"os"
"time"
)
func main() {
var err error
ch1 := make(chan []byte)
ch2 := make(chan int)
var buf []byte
var i int
var ok bool
go reader(ch1)
go counter(ch2)
for {
select {
case buf, ok = <-ch1:
if ok {
_, err = os.Stdout.Write([]byte("input: "))
_, err = os.Stdout.Write(buf)
}
case i, ok = <-ch2:
if ok {
_, err = fmt.Println("count", i)
}
}
if err != nil {
fmt.Println("error", err)
}
if !ok {
break
}
}
}
func counter(ch chan<- int) {
i := 0
for i < 5 {
i++
ch <- i
time.Sleep(time.Second)
}
close(ch)
}
func reader(ch chan<- []byte) {
var r int
var err error
for {
buf := make([]byte, 4000)
r, err = os.Stdin.Read(buf)
if r > 0 {
ch <- buf[:r]
}
if err != nil {
fmt.Println("read error", err)
if err == io.EOF {
break
}
// Or really just about any error on read is fatal
break
}
}
close(ch)
}