我正在使用SOCK_STREAM
从c程序写入正在从go程序中收听的Unix域套接字net.Listen("unix", sockname)
。当我使用O_NONBLOCK
将套接字设置为fcntl()
时,我看到C程序在第一次写入时只写入8192个字节。失败后,我会监视并回写剩余数据,但在这种情况下,我服务器上的读取数据无效。
当我不使用O_NONBLOCK
时,整个8762字节都写入一次写入,一切都按预期工作。
C客户端套接字连接
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
return;
}
int flags = fcntl(fd, F_GETFL, 0);
flags = flags|O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
...
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
return;
}
C客户端写作
while (written < to_write) {
int result;
if ((result = write(fd, &buffer[written], to_write - written)) < 0) {
if (errno == EINTR) {
continue;
}
if (errno == EAGAIN) {
struct pollfd pfd = { .fd = fd, .events = POLLOUT };
poll_count++;
if (poll_count > 3) {
goto end;
}
if ((poll(&pfd, 1, -1) <= 0) && (errno != EAGAIN)) {
goto end;
}
continue;
}
end:
return written ? written : result;
}
written += result;
buffer += result;
}
去服务器阅读
buf := make([]byte, 0, count)
var tmpsize int32
for {
if count <= 0 {
break
}
if count > 100 {
tmpsize = 100
} else {
tmpsize = count
}
tmp := make([]byte, tmpsize)
nr, err = conn.Read(tmp)
if err != nil {
return
}
buf = append(buf, tmp[:nr]...)
count = count - int32(nr)
}
我在这里缺少什么。我在OSX上运行它。我也尝试将Go Server中的SO_SNDBUF
设置为10000,但它没有帮助
err = syscall.SetsockoptInt(int(fd.Fd()), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 10000)
if err != nil {
return
}
答案 0 :(得分:0)
我要做的是将数据直接读入bytes.Buffer
,类似于此处列出的答案:
https://stackoverflow.com/a/24343240/8092543
https://golang.org/pkg/io/#Copy
io.Copy
的美妙之处在于它使用了Writer + Reader界面,但是你的bytes.Buffer
(io.Writer)和你的conn.Read
(io.Reader)非常满意。用......之类的东西替换整个块。
var buf bytes.Buffer
count, err := io.Copy(buf, conn)
if err != nil {
return nil, fmt.Errorf("error during conn read: %v", err)
}
return buf.Bytes(), nil
答案 1 :(得分:0)
这是正常行为。非阻塞写入只能传输适合套接字发送缓冲区的数据。如果您得到一个简短的计数,您需要循环或选择可写性并重试。另一方面,阻塞写入总是传输整个数据。
在Unix域套接字上设置发送缓冲区大小可能无效。