在这个最小的示例程序中读取发送unix数据报域套接字的地址时,我得到的地址长度为0,但unix域套接字的手册页指定:
unnamed:未使用绑定到路径名的流套接字 bind(2)没有名字。同样,套接字创建的两个套接字 - 对(2)未命名。当未命名的套接字的地址是 返回,其长度为sizeof(sa_family_t),sun_path不应该 被检查。
我希望根据此手册页将未命名的套接字的地址长度设置为2。我是否误解了手册页,手册页是否不适用于SOCK_DGRAM
类型的unix套接字,或者我只是错误地读取了长度?
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
// or for pathnamed socket
// const char SOCK_NAME[] = "/tmp/test.uds";
const char PAYLOAD[] = "Hello!";
int main() {
int rx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (rx_sock < 0) {
perror("Create RX");
exit(1);
}
int tx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (tx_sock < 0) {
perror("Create TX");
exit(1);
}
struct sockaddr_un bind_addr;
bind_addr.sun_family = AF_UNIX;
memcpy(bind_addr.sun_path, SOCK_NAME, sizeof(SOCK_NAME));
socklen_t bind_len = sizeof(sa_family_t) + sizeof(SOCK_NAME);
if (bind(rx_sock, (const struct sockaddr *)&bind_addr, bind_len) != 0) {
perror("Bind RX");
exit(1);
}
if (sendto(tx_sock, PAYLOAD, sizeof(PAYLOAD), 0, (const struct sockaddr *)&bind_addr, bind_len) < 0) {
perror("Sendto");
exit(1);
}
// For pathnamed socket
// unlink(SOCK_NAME);
struct sockaddr_un recv_addr;
socklen_t recv_len = sizeof(recv_addr);
char buffer[1024];
ssize_t rx_count = recvfrom(rx_sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&recv_addr, &recv_len);
if (rx_count < 0) {
perror("Recvfrom");
exit(1);
}
printf("Address size of TX on receiver side: %d\n", recv_len); // 0
recv_len = sizeof(recv_addr);
if (getsockname(tx_sock, (struct sockaddr *)&recv_addr, &recv_len) != 0) {
perror("getsockname");
exit(1);
}
printf("Address size of TX on sender side: %d\n", recv_len); // 2
}
答案 0 :(得分:2)
你有未命名的未绑定的Unix域数据报套接字tx_sock
,以及绑定到rx_sock
中的抽象地址的Unix域数据报套接字bind_path
。
注意:根据man 7 unix
,Linux中未绑定的Unix域流套接字未命名,其地址长度为sizeof (sa_family_t)
。根据POSIX.1,unbound socket addresses are unspecified,所以我们真的需要注意我们对未绑定套接字地址及其长度的期望。在这种特殊情况下,在Linux中,使用手册页作为指南,未绑定的Unix域数据报套接字没有地址,因此其长度为零。 (甚至有意义:零地址长度表示你无法回复发件人。对于未绑定的流套接字,有一个连接回发送者的连接,但没有其他方式来回复发送者但连接本身;这就是为什么在那个地址长度非零,sizeof (sa_family_t)
。)
摘要Unix域套接字地址是Linux扩展;它们以NUL字节(\0
)开头,在文件系统中不可见。
您使用sendto(tx_sock, msg, msg_len, 0, bind_path, bind_path_len)
发送消息。
您使用recvfrom(rx_sock, buffer, sizeof buffer, 0, &recv_addr, &recv_addrlen)
接收邮件(recv_addrlen
已正确初始化为sizeof recv_addr
)。
由于tx_sock
未绑定到任何地址,因此未命名未绑定:它没有地址,无法回复,因此recv_addrlen == 0
。
如果您添加代码以将tx_sock
绑定到其他某个摘要地址,您将在recv_addr
和recv_addrlen
中收到该地址。
(我使用四个线程的测试程序验证了这种行为,其中每个线程向另一个线程发送消息,并打印所有收到的消息以及它们来自哪里,使用标准地址和抽象地址。一切都按照记录的方式工作。)
答案 1 :(得分:-2)
当然,你的名字长度为零。
char
数组中的第一个值是0
,立即将字符串终止为零字节长度:
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
unnamed:未使用bind(2)绑定到路径名的流套接字没有名称。
不适用,因为 使用bind()
绑定套接字: