操作系统何时会关闭已连接的 UDP 套接字?
我在 Linux 下运行的 C++ 程序中有一个 UDP 文件描述符。我对其调用 connect()
将其连接到远程地址,然后从该套接字读取和写入。
根据 UNIX 网络编程,“异步错误将返回到已连接的 UDP 套接字的进程”。我猜测这些异步错误将导致 UDP 套接字被操作系统关闭,但书上并没有那么清楚。目前还不清楚可能出现哪些类型的异步错误,但建议如果远程计算机上的端口未打开,则套接字将被关闭。
所以我的问题是:Linux在什么情况下会关闭UDP文件描述符?
- 端口号错误?
- IP 地址错误?
- 还有其他人吗?
I have a UDP file descriptor in a C++ program running under Linux. I call connect()
on it to connect it to a remote address and then read and write from that socket.
According to UNIX Network Programming, "Asynchronous errors are returned to the process for connected UDP sockets." I'm guessing that these asynchronous errors will cause the UDP socket to be closed by the OS, but the book isn't that clear. It also isn't clear what types of asynchronous errors are possible, though it's suggested that if the port on the remote machine is not open, the socket will be closed.
So my question is: Under what conditions will Linux close the UDP file descriptor?
- Bad port number?
- Bad IP address?
- Any others?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
UDP 套接字上的 connect() 只记录您传入的端口号和 IP 地址,因此它只会接受来自该 IP/端口的数据包,并且您可以使用套接字 fd 发送/写入数据,而无需指定远程地址每次发送/写入调用。
关于这一点,异步错误意味着如果您 send() 某些内容,并且该发送调用导致稍后发生错误(例如,当 TCP/IP 堆栈实际发送数据包时,或者稍后返回 ICMP 数据包时),后续发送将返回那个错误。此类异步错误仅在“已连接”UDP 套接字上返回。 (linux udp(7) 手册页建议无论套接字是否连接都会返回错误,但测试表明至少在发送的 UDP 数据包生成 ICMP 错误时并非如此。可能是返回 send() 错误如果您在该套接字上使用 recv(),而不是后续的 send() 调用会产生错误,
则套接字尚未关闭,您必须通过调用 close() 或退出程序自行关闭它。例如,如果您 connect() UDP 套接字,并发送到无人监听的端口,则通常会返回 ICMP 数据包,并且后续的 send() 调用将失败,并将 errno 设置为 ECONNREFUSED。不过,您可以继续在该套接字上发送,它不会被操作系统关闭,并且如果有人同时开始侦听该端口,数据包将通过。
connect() on an UDP socket just records the port number and IP address you pass in, so it'll only accept packets from that IP/port, and you can use the socket fd to send/write data without specifying the remote address for each send/write call.
Regarding this, async errors means if you send() something, and that send call results in an error occuring later (e.g. when the TCP/IP stack actually sends the packet, or an ICMP packet is later returned), a subsequent send will return that error. Such async errors are only returned on a "connected" UDP socket. (The linux udp(7) manpage suggest errors are returned whether the socket is connected or not, but testing shows this is not the cases at least when a sent UDP packet generates an ICMP error. It might be that send() errors are returned if you recv() on that socket, instead of subsequent send() calls produce an error )
The socket is not closed though, you'll have to close it yourself either by calling close() or exiting the program. e.g. if you connect() your UDP socket, and send to a port noone is listening to, an ICMP packet is normally returned and a subsequent send() call will fail with errno set to ECONNREFUSED. You can continue sending on that socket though, it doesn't get closed by the OS, and if someone starts listening on the port in the mean time the packets will get through.
UDP 套接字是无连接的,因此它们没有真正意义上的“开放”状态 - 这与 TCP 套接字不同,在 TCP 套接字中,套接字可以处于任意数量的连接状态,这取决于给定点的数据包交换。
UDP 套接字可以打开和关闭的唯一意义是它们是具有某些内部状态和文件描述符的系统级对象。发生错误时,套接字永远不会自动关闭,并将无限期地保持打开状态,除非其所属进程终止或对其调用
close
。为了解决您的另一个问题,如果目标主机上的目标端口未打开,UDP 数据包的发送方将永远不会知道。** UDP 不提供接收方确认的方法。数据包被路由,如果它到达主机,则检查其正确性并成功接收或丢弃。在写入 UDP 套接字时,
send
可能会返回错误代码,原因有很多,但这些原因都与接收主机的状态无关。** 我建议查阅sendto
手册页了解可能的故障模式。另一方面,如果 TCP 套接字尝试连接到未打开的端口,则发送方将永远不会收到对其初始连接请求的确认,并且最终
connect
将失败。此时,发送方应停止通过套接字发送数据(因为这只会产生更多错误),但即使在这种情况下,套接字文件描述符也永远不会自动关闭。** 请参阅评论中 @Zuljin 的回复。
UDP sockets are connectionless, so there is no real sense of "openness" state attached to them - this is unlike TCP sockets where a socket may be in any number of connection states as determined by the exchange of packets up to a given point.
The only sense in which UDP sockets can be opened and closed is in the sense that they are system level objects with some internal state and a file descriptor. Sockets are never automatically closed in the event of an error and will remain open indefinitely, unless their owning process terminates or calls
close
on them.To address your other concern, if the destination port on the destination host is not opened, the sender of a UDP packet will never know.** UDP provides no means of receiver acknowledgement. The packet is routed and, if it arrives at the host, checked for correctness and either successfully received or discarded. There are a number of reasons why
send
might return an error code when writing to a UDP socket, but none of them have to do with the state of the receiving host.** I recommend consulting thesendto
manpage for possible failure modes.On the other hand, in the case of a TCP socket attempting to connect to an unopened port, the sender will never receive an acknowledgement of its initial connection request, and ultimately
connect
will fail. At this point it would be up to the sender to stop sending data over the socket (as this will only generate more errors), but even in this case however, the socket file descriptor is never automatically closed.** See response by @Zuljin in the comments.
操作系统不会仅仅因为发生错误就关闭您的套接字。如果另一端消失,您可以继续向其发送消息(但可能会收到更多错误)。
The OS won't close your socket just because an error has happened. If the other end disappears, you can continue to send messages to it (but may receive further errors).