gpt4 book ai didi

c++ - 为什么设置为 sockaddr_un::sun_path[0] 的文件名要偏移 1?

转载 作者:行者123 更新时间:2023-11-30 03:31:47 27 4
gpt4 key购买 nike

我正在学习套接字编程。以下代码基于示例,旨在演示套接字连接的基础知识。

#include <iostream>
#include <cerrno>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdint.h>
#include <sstream>
#include <stdexcept>
#include <fcntl.h>
#include <cstdio>
#include <sys/un.h>
#include <cstdlib>
#include <sstream>

#define ASSERT( EXPRESSION ) \
{ \
if ( ! ( EXPRESSION ) ) \
{ \
std::ostringstream oss; \
oss << "Expression \"" << #EXPRESSION << "\" failed at line " << __LINE__ \
<< "; errno == " << errno << " (" << strerror( errno ) << ")"; \
throw std::runtime_error( oss.str() ); \
} \
}

int main( int argc, char* argv[] )
{
int ret_val = 0;
int sd;
char socket_pathname[ L_tmpnam ];

try
{
errno = 0;

// Create a socket
sd = socket( AF_LOCAL, SOCK_STREAM, 0 );
ASSERT( sd >= 0 );

ASSERT( NULL != tmpnam( socket_pathname ) );
ASSERT( strlen( socket_pathname ) < sizeof( ((struct sockaddr_un*)0)->sun_path ) - 1 );

// Create socaddr_un, "derived class" of sockaddr.
struct sockaddr_un su;
su.sun_family = AF_LOCAL;
strncpy( su.sun_path + 1, socket_pathname, sizeof( su.sun_path ) );
su.sun_path[ 0 ] = 'Z';

int su_len = SUN_LEN( &su );
su.sun_path[0] = '\0'; // Why???

// bind address to socket.
int result = bind( sd, (struct sockaddr*)&su, su_len );
ASSERT( -1 != result );

std::cout << "Socket pathname: " << socket_pathname << std::endl;
std::cout << "Socket pathname2: " << su.sun_path + 1 << std::endl;

system( "netstat -pa --unix 2>/dev/null | sed -n '/Active UNIX/,/^Proto/p;/a.out/p'" );
}
catch( std::runtime_error& e )
{
std::cout << e.what() << std::endl;
ret_val = 1;
}

if ( sd >= 0 ) close( sd );
remove( socket_pathname );

return ret_val;
}

我不明白为什么 sockaddr_un::sun_path 中设置的文件名需要偏移 1。这是一个奇怪的约定,无论是我正在学习的示例还是其他阅读 Material 解释了这背后的目的。谁能解释一下?

此外,在调用 SUN_LEN() 之前,如果我将 sockaddr_un::sun_path[0] 设置为 \0,生成的路径名与我的套接字相关联的似乎是一个以 "@" 为前缀的递增数字,例如@00017@00018 等。看来 sockaddr_un::sun_path[0] 必须是除 0 之外的某个 ASCII 值 - 为什么会这样?是否期望有任何特定值?如果我将它更改为其他非 NULL 值,它对程序行为没有明显的影响。

最佳答案

答案在以下 Linux 联机帮助页中:

http://man7.org/linux/man-pages/man7/unix.7.html

The AF_UNIX (also known as AF_LOCAL) socket family is used to communicate between processes on the same machine efficiently. Traditionally, UNIX domain sockets can be either unnamed, or bound to a filesystem pathname (marked as being of type socket). Linux also supports an abstract namespace which is independent of the filesystem.

...

Three types of address are distinguished in the sockaddr_un structure:

  • pathname: a UNIX domain socket can be bound to a null-terminated filesystem pathname using bind(2). When the address of a pathname socket is returned (by one of the system calls noted above), its length is offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 and sun_path contains the null-terminated pathname. (On Linux, the above offsetof() expression equates to the same value as sizeof(sa_family_t), but some other implementations include other fields before sun_path, so the offsetof() expression more portably describes the size of the address structure.)

    For further details of pathname sockets, see below.

  • unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name. Likewise, the two sockets created by socketpair(2) are unnamed. When the address of an unnamed socket is returned, its length is sizeof(sa_family_t), and sun_path should not be inspected.

  • abstract: an abstract socket address is distinguished (from a pathname socket) by the fact that sun_path[0] is a null byte ('\0'). The socket's address in this namespace is given by the additional bytes in sun_path that are covered by the specified length of the address structure. (Null bytes in the name have no special significance.) The name has no connection with filesystem pathnames. When the address of an abstract socket is returned, the returned addrlen is greater than sizeof(sa_family_t) (i.e., greater than 2), and the name of the socket is contained in the first (addrlen - sizeof(sa_family_t)) bytes of sun_path.

因此,sun_path[0] 用于区分绑定(bind)路径名套接字地址和抽象套接字地址。如果 sun_path[0] 为 0,则地址是抽象的。否则,整个 sun_path(包括 sun_path[0])是一个文件系统路径。

关于c++ - 为什么设置为 sockaddr_un::sun_path[0] 的文件名要偏移 1?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43947721/

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