关于BSD与Linux UDP套接字因操作系统介入导致描述符失效的场景咨询
Hey there! Let's tackle your two questions about UDP socket descriptor invalidation—this is the kind of low-level kernel behavior that's often glossed over in basic socket docs, so I get why you're digging for details.
On BSD systems, the kernel will invalidate a UDP socket descriptor in these specific scenarios (no action required from your application):
- Process exit (normal or abnormal): If your process crashes, is killed via a signal like
SIGKILL, or exits cleanly withexit(), the kernel automatically closes all open file descriptors—including UDP sockets. This is the most common case; the kernel handles cleanup to prevent resource leaks. - Resource limit enforcement: If your process hits the per-process open file descriptor limit (
RLIMIT_NOFILE), you won't be able to create new sockets, but existing ones stay valid. However, in extreme cases of system-wide resource exhaustion, the kernel might terminate your process (viaSIGKILL), which then leads to descriptor invalidation as part of process cleanup. - External tool intervention: If a system tool or debugger (e.g.,
gdbattaching and callingclose()on the descriptor, orfusersending a termination signal) forces the descriptor closed or kills the process holding it, this counts as OS-level intervention. - Kernel panic/crash recovery: After a system crash, all socket descriptors are invalidated since the process is restarted (if configured to do so) or terminated entirely.
Your question about EBADF (invalid file descriptor) and ENOTASOCK (descriptor is not a socket) errors when the app did nothing wrong is tricky—Linux generally doesn't arbitrarily invalidate valid descriptors, but there are a few edge cases where this can happen:
- Forgotten
FD_CLOEXECflag on exec: If your process callsexec()to replace its image without setting theFD_CLOEXECflag on the UDP socket descriptor, the descriptor remains open in the new process. But if the new process isn't expecting that descriptor (e.g., it's a different binary that reuses the descriptor number for a regular file), you'll getENOTASOCKwhen trying to use it as a socket. While technically the original app could have setFD_CLOEXEC, this is a common pitfall where the error feels like it's coming from the kernel rather than app logic. - Stale descriptor reuse: If your process closed a socket descriptor, and the kernel later reassigns that same number to a new file or non-socket descriptor, any stale references in your app to the old number will trigger
EBADForENOTASOCK. While this is technically an app error for keeping stale references, it can feel like kernel behavior if the reuse happens unexpectedly. - Kernel bugs (rare): In rare cases, kernel bugs can incorrectly mark a valid socket descriptor as invalid, leading to these errors. This is extremely uncommon, but worth checking if you're running an older kernel version—upgrading might resolve the issue.
- Seccomp filter blocking (security policy): If your process is subject to a seccomp filter that blocks socket operations, attempts to use a valid socket descriptor might return
EBADFor similar errors. This is a kernel-enforced security measure, not an app error if you didn't configure the filter yourself.
One key note: UDP is connectionless, so the kernel will never close a UDP socket due to protocol-level errors (unlike TCP, which closes sockets on connection failures). Any invalidation of a UDP socket descriptor on Linux is almost always tied to process lifecycle, resource limits, or external/system-level actions.
内容的提问来源于stack exchange,提问作者veer

