套接字:为什么阻塞 read() 会因 ENOTCONN 失败?
我正在尝试从阻塞套接字读取数据,但我想知道 read()
返回 -1,我认为这意味着当前没有数据可读取 - 我希望它会阻塞,直到它可以读取字节数。
我还尝试确保套接字处于阻塞模式,并使用以下命令设置高超时:
int setBlockingIO(int fd)
{
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags & (~O_NONBLOCK));
int nTimeout = 30000; // 30 seconds
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTimeout, sizeof(int));
}
但这并没有改变任何内容。
我的问题:
- 我必须做什么,
read()
才会真正阻塞?
- 我可能会遇到一些陷阱吗? (我的程序中存在错误?)
我知道关于此主题还有另一个问题,但我在那里找不到我的问题的答案。
UPDATE
在不设置超时的情况下,read()
也会立即返回(主观地)-1
UPDATE 2
errno
为 107 (ENOTCONN,传输端点未连接)
。 但客户端同时还没有关闭连接(通过 write()
之后长时间的 sleep()
确保)
I am trying to read from a blocking socket, but I am wondering that read()
returns -1, which I think means that there's currently no data to read - I would expect that it blocks until it can read the amount of bytes.
I also tried ensuring that the socket is in blocking mode and that a high timeout is set using:
int setBlockingIO(int fd)
{
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags & (~O_NONBLOCK));
int nTimeout = 30000; // 30 seconds
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTimeout, sizeof(int));
}
But this hasn't changed anything.
My question:
- What do I have to do that
read()
willreally block?
- Are there some pitfalls which I might hit? (bug in my program?)
I know that there's another question on this topic, but there I cannot find the answer for my question.
UPDATE
Without setting a timeout, read()
also returns (subjectivly) immediately -1
UPDATE 2
errno
is 107 (ENOTCONN, Transport endpoint is not connected)
.
But the client side has not closed the connection in the meanwhile (ensured by a long sleep()
after write()
)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
你期望什么?你说你有一个非阻塞套接字,所以它当然不会阻塞。非阻塞套接字在读取时的行为是,如果有数据可供读取,则立即返回一些数据(可能比请求的数量短),并返回 -1 和 errno<如果没有可用数据,/code> 设置为
EAGAIN
或EWOULDBLOCK
。如果您不想要非阻塞行为,为什么要将套接字设置为非阻塞?
编辑: 呃,你改变了你的问题。
ENOTCONN
的原因是您试图从未连接的套接字读取数据。除非套接字是通过accept
或socketpair
获得的,否则您必须在read< 之前对其调用
connect
以将其连接到远程地址/code> 会起作用。What do you expect? You said you have a non-blocking socket so of course it does not block. The behavior for a non-blocking socket on
read
is to immediately return with some data (possibly shorter than the requested amount) if data is available to read, and to return -1 witherrno
set toEAGAIN
orEWOULDBLOCK
if no data is available.If you don't want non-blocking behavior, why did you set the socket to be non-blocking?
Edit: Grr, you've changed your question. The reason for
ENOTCONN
is that you're trying to read from a socket that is not connected. Unless a socket was obtained byaccept
orsocketpair
, you must callconnect
on it to connect it to a remote address beforeread
will work.这意味着要么超时,要么可能有信号中断读取。您可以使用 errno.h 中的 errno 的结果来查看错误是什么,如果您希望以人类可读的格式显示错误,则可以使用 <来自
string.h
或stdlib.h
的 code>strerror() 或perror()
更新: 根据 POSIX 规范,您应该传递一个
struct timeval
(在sys/time.h
中定义)在指定时设置为setsockopt
发生超时之前所需的秒数和微秒数SO_RCVTIMEO
标志,而不是将int
转换为const char*
。因此,即使您的客户端现在可能行为不当并导致不同的错误,如果您向函数发送错误的参数类型,您仍然可能最终遇到问题。It means that either there was a time-out, or possibly a signal interrupted the read. You can use the results of
errno
inerrno.h
to see what the error is, and if you want the error in a human-readable formating, you can use eitherstrerror()
orperror()
fromstring.h
orstdlib.h
Update: According to the POSIX specification, you should be passing a
struct timeval
(defined insys/time.h
) set to the desired number of seconds and microseconds before a timeout occurs tosetsockopt
when specifying theSO_RCVTIMEO
flag rather than casting anint
to aconst char*
. So even though your client may be mis-behaving and causing a different error right now, you could still end up with problems further down the line if you're sending the wrong argument types to the function.原因就在errno中。可能的情况:
[ECONNRESET]
d 参数指的是套接字,而远程套接字端被强制关闭。
[EAGAIN]
文件被标记为非阻塞 I/O,并且没有数据已准备好阅读。
基本上,您可以使用以下方法进行非阻塞阻塞:
The reason is in errno. Likely scenarios:
[ECONNRESET]
The d argument refers to a socket, and the remotesocket end is forcibly closed.
[EAGAIN]
The file was marked for non-blocking I/O, and no datawere ready to be read.
Basically, you make non-blocking blocking using:
超时时返回-1。
不要设置超时,它将永远阻塞(至少在套接字仍处于连接状态时)。
It returns -1 when it times out.
Don't set a timeout and it will block forever (Well, at least while the socket is still connected, anyway).
我已经解决了这个问题。
感谢您的所有评论,它们给了我们很大的帮助。
问题在于使用了错误的文件描述符。
我将服务器套接字的文件描述符传递给
read()
,而不是accept(的客户端套接字的文件描述符) )
返回。I've solved the problem.
Thank you for all your comments, they had been a great help.
The problem was the usage of the wrong file descriptor.
I passed the file descriptor of the server socket to
read()
, instead of the file descriptor of the client socket whichaccept()
returned.read()
可能会阻塞,因此如果没有可用数据,它将返回-1
并将errno
设置为EAGAIN
或EWOULDBLOCK
。如果您想使用
read()
,您可以使用select()
或poll()
来等待套接字上数据的可用性。read()
could block, so if there's no data available it will return-1
and seterrno
toEAGAIN
orEWOULDBLOCK
.If you wand to use
read()
, you could useselect()
orpoll()
to wait for availability of data on the socket.