C 未命名的unix域套接字的地址长度错误
在这个最小示例程序中读取发送unix数据报域套接字的地址时,我得到的地址长度为0,但unix域套接字的手册页指定: 未命名:未使用绑定到路径名的流套接字 绑定(2)没有名称。同样,套接字创建的两个套接字 对(2)未命名。当未命名套接字的地址为 返回时,其长度为sizeof(sau family),sun_路径不应为 接受检查 基于此手册页,我希望未命名套接字的地址长度为2。我是否误解了手册页,手册页是否不适用于类型为C 未命名的unix域套接字的地址长度错误,c,linux,C,Linux,在这个最小示例程序中读取发送unix数据报域套接字的地址时,我得到的地址长度为0,但unix域套接字的手册页指定: 未命名:未使用绑定到路径名的流套接字 绑定(2)没有名称。同样,套接字创建的两个套接字 对(2)未命名。当未命名套接字的地址为 返回时,其长度为sizeof(sau family),sun_路径不应为 接受检查 基于此手册页,我希望未命名套接字的地址长度为2。我是否误解了手册页,手册页是否不适用于类型为SOCK_DGRAM的unix套接字,或者我只是错误地读取了长度 #includ
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
}
#包括
#包括
#包括
#包括
const char SOCK_NAME[]={0',t',e',s',t'};
//或用于名为socket的路径
//const char SOCK_NAME[]=“/tmp/test.uds”;
const char PAYLOAD[]=“你好!”;
int main(){
int rx_sock=socket(AF_UNIX,sock_DGRAM,0);
如果(rx_sock<0){
perror(“创建RX”);
出口(1);
}
int tx_sock=socket(AF_UNIX,sock_DGRAM,0);
如果(tx_sock<0){
perror(“创建TX”);
出口(1);
}
结构sockaddr\u unbind\u addr;
bind_addr.sun_family=AF_UNIX;
memcpy(bind_addr.sun_路径、SOCK_名称、sizeof(SOCK_名称));
socklen\u t bind\u len=sizeof(sau家族)+sizeof(SOCK\u名称);
if(绑定(rx_sock,(const struct sockaddr*)和绑定地址,绑定长度)!=0){
perror(“绑定RX”);
出口(1);
}
if(发送到(发送套接字,有效负载,大小(有效负载),0,(常量结构sockaddr*)和绑定地址,绑定长度)<0){
perror(“Sendto”);
出口(1);
}
//对于路径名套接字
//取消链接(袜子名称);
结构sockaddr\u un recv\u addr;
socklen_t recv_len=sizeof(recv_addr);
字符缓冲区[1024];
ssize_t rx_count=recvfrom(rx_sock,buffer,sizeof(buffer),0,(struct sockaddr*)和recv_addr,&recv_len);
如果(rx_计数<0){
perror(“Recvfrom”);
出口(1);
}
printf(“接收方发送的地址大小:%d\n”,recv_len);//0
recv_len=sizeof(recv_addr);
if(getsockname(tx_sock,(struct sockaddr*)&recv_addr,&recv_len)!=0){
perror(“getsockname”);
出口(1);
}
printf(“发送方发送的地址大小:%d\n”,recv_len);//2
}
当然,名称长度为零
char
数组中的第一个值是0
,立即将字符串终止为零字节:
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
未命名:未使用bind(2)绑定到路径名的流套接字没有名称
不适用,因为您正在使用bind()
绑定套接字:您有一个未命名的未绑定Unix域数据报套接字tx\u sock
,以及一个绑定到bind\u路径中的抽象地址的Unix域数据报套接字rx\u sock
注意:根据,未绑定的Unix域流套接字在Linux中未命名,其地址长度将为sizeof(sa_family\u t)
。根据POSIX.1,所以我们确实需要小心我们对未绑定套接字地址及其长度的期望。在这种特殊情况下,在Linux中,使用手册页作为指南,未绑定的Unix域数据报套接字没有地址,因此其长度为零。(这甚至是有意义的:零地址长度表示您无法回复发件人。使用未绑定的流套接字,可以连接回发件人,但除了连接本身,没有其他方式回复发件人;这就是为什么在这种情况下,地址长度不为零,sizeof(sa_family_t)
)
抽象Unix域套接字地址是Linux扩展;它们以NUL字节(\0
)开头,在文件系统中不可见
您可以使用sendto(tx\u sock,msg,msg\u len,0,bind\u path,bind\u path\u len)
发送消息
您使用recvfrom(rx\u sock,buffer,sizeof buffer,0,&recv\u addr,&recv\u addrlen)
接收消息(使用recv\u addrlen
正确初始化为sizeof recv\u addr
)
由于tx\u sock
未绑定到任何地址,因此未命名未绑定:它没有地址,无法回复,因此recv\u addrlen==0
如果您添加代码将tx\u sock
绑定到其他抽象地址,您将在recv\u addr
和recv\u addrlen
中收到该地址
(我用一个使用四个线程的测试程序验证了这一行为,其中每个线程向另一个线程发送一条消息,并打印所有接收到的消息以及它们的来源,包括标准地址和抽象地址。一切都按文档所述进行。)小问题:sizeof(有效负载)
应该是strlen(有效载荷)
。你在那里得到了指针的大小。否则,这是一个很好的问题。这似乎是一个内核错误。如果行为符合预期,则手册页需要更新。如果你将SOCK\u名称
设置为/tmp/socktest
这样的真实路径,并在绑定
之前添加了一个取消链接
,那么你就拥有了一些可移植的东西到其他没有“抽象命名空间”的Unice。看看他们是否做了同样的事情会很有趣。不清楚的地方没有名字
,sun_path不应该被检查
?你为什么试图写入它?@stark我正在写入路径以将接收套接字绑定到摘要address@WumpusQ.Wumbley感谢您指出这一点,我制作了PAYLOAD
代码中的数组使用了正确的大小。我还尝试使用名为socket的路径,该地址在接收端的长度也为0side@MaxBenson:发送套接字未命名。接收方已知道其绑定到的地址。recvfrom()
返回发送方ad