gpt4 book ai didi

c - 不明白为什么 APUE 的代码片段会取消链接附加到客户端 unix 域套接字的文件

转载 作者:行者123 更新时间:2023-12-01 23:36:06 25 4
gpt4 key购买 nike

书中定义了3个自定义函数:

int serv_listen(const char *name);
//Returns: file descriptor to listen on if OK, negative value on error

int serv_accept(int listenfd, uid_t *uidptr);
//Returns: new file descriptor if OK, negative value on error

int cli_conn(const char *name);
//Returns: file descriptor if OK, negative value on error

The serv_accept function (Figure 17.9) is used by a server to wait for a client’s connect request to arrive. When one arrives, the system automatically creates a new UNIX domain socket, connects it to the client’s socket, and returns the new socket to the server. Additionally, the effective user ID of the client is stored in the memory to which uidptr points.


serv_accept函数代码及说明:

#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <errno.h>

#define STALE 30 /* client's name can't be older than this (sec) */

/*
* Wait for a client connection to arrive, and accept it.
* We also obtain the client's user ID from the pathname
* that it must bind before calling us.
* Returns new fd if all OK, <0 on error
*/
int
serv_accept(int listenfd, uid_t *uidptr)
{
int clifd, err, rval;
socklen_t len;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
char *name;

/* allocate enough space for longest name plus terminating null */
if ((name = malloc(sizeof(un.sun_path + 1))) == NULL)
return(-1);
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) {
free(name);
return(-2); /* often errno=EINTR, if signal caught */
}

/* obtain the client's uid from its calling address */
len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
memcpy(name, un.sun_path, len);
name[len] = 0; /* null terminate */
if (stat(name, &statbuf) < 0) {
rval = -3;
goto errout;
}

#ifdef S_ISSOCK /* not defined for SVR4 */
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = -4; /* not a socket */
goto errout;
}
#endif

if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
(statbuf.st_mode & S_IRWXU) != S_IRWXU) {
rval = -5; /* is not rwx------ */
goto errout;
}

staletime = time(NULL) - STALE;
if (statbuf.st_atime < staletime ||
statbuf.st_ctime < staletime ||
statbuf.st_mtime < staletime) {
rval = -6; /* i-node is too old */
goto errout;
}

if (uidptr != NULL)
*uidptr = statbuf.st_uid; /* return uid of caller */
unlink(name); /* we're done with pathname now */
free(name);
return(clifd);

errout:
err = errno;
close(clifd);
free(name);
errno = err;
return(rval);
}

... Then we call stat to verify that the pathname is indeed a socket and that the permissions allow only user-read, user-write, and user-execute. We also verify that the three times associated with the socket are no older than 30 seconds.

If all these checks are OK, we assume that the identity of the client (its effective user ID) is the owner of the socket.

为什么服务器代码 unlink(name) 附加到客户端套接字的文件?

其他2个函数代码通过链接提供:

https://wandbox.org/permlink/jq5BajJYLgoh4yO6

最佳答案

Why does the server code unlink(name) the file attached to the client's socket?

更准确的说法是服务器正在删除附加到客户端套接字的文件路径。或者更通俗地说,客户端的套接字名称。

回想一下 unlink() 不会删除当前在某些进程中打开的命名对象;客户端的套接字大概在客户端中仍处于打开状态,因此 unlink(name) 尚未删除套接字。相反,它确保套接字在不再被正在运行的进程使用时将被删除。

它立即做的是释放名称,以便名称可以在不同的套接字中重用。

那为什么要这样做呢?主要是为了使文件系统不会被僵尸套接字名称填满。它无助于当前客户端重用该名称(例如连接到不同的服务),因为客户端无论如何都会在尝试使用该名称之前取消链接。但是僵尸名称对于具有不同 uid 的不同 future 客户端进程来说可能是一个问题,而这些进程恰好被分配了相同的 pid。 future 的进程可能没有足够的权限取消名称的链接,在这种情况下,它将最终无法使用此 IPC 机制(至少对于此库)。

好的,那么为什么它被服务器取消链接?服务器使用 stat 调用的文件路径,而客户端无法知道这种情况何时发生。由于尽快解除名称链接基本上是个好主意,在这种情况下服务器最好解除名称链接;它知道何时不再需要该名称。

当然,所提供的代码并不完美。有些执行路径会导致某些名称无法取消链接(例如,如果服务器进程在错误的时间崩溃)。但这些应该很少见。经验表明,客户端崩溃的频率远高于服务器。

关于c - 不明白为什么 APUE 的代码片段会取消链接附加到客户端 unix 域套接字的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59463482/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com