connect
的手册说:
如果套接字sockfd的类型为SOCK_DGRAM,则addr是默认发送数据报的地址,也是接收数据报的唯一地址。
以下C程序似乎在UNIX域套接字上显示connect
/ recv
的Linux实现中的错误,因为它从除了@"PWE0"
之外的地址接收消息它连接到的那个(@"STAR"
),并终止。与此相反,我期望的行为是程序不会终止,因为它忠实地等待来自它已连接到的地址的消息,该地址永远不会到达。 (我故意不会使用返回值检查和打印语句来混淆示例,因为它可以使用strace
轻松检查;在现实生活中,调用将由不同的进程进行。)
#include <sys/socket.h>
char header[] = "PLD ";
int main()
{
#define addrlen sizeof(unsigned short) + sizeof (char [1+4]) + sizeof(int)
int fd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(fd, &(struct sockaddr){ AF_UNIX, "\0PLD " }, addrlen);
int gd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(gd, &(struct sockaddr){ AF_UNIX, "\0STAR" }, addrlen);
int hd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(hd, &(struct sockaddr){ AF_UNIX, "\0PWE0" }, addrlen);
sendto(hd, "PWE0\0\0\0\n\1h\0\0\0\1\0\0\0\1", 18, 0,
&(struct sockaddr){ AF_UNIX, "\0PLD " }, addrlen);
connect(fd, &(struct sockaddr){ AF_UNIX, "\0STAR" }, addrlen);
char buf[32];
return recv(fd, buf, sizeof buf, 0);
}
那么,Linux [以及HP-UX(带有文件系统路径名)]是否违反规范,或者我错过了什么?
答案 0 :(得分:2)
编辑我注意到我的第一个回答是错误的。所以我编辑了很多文本。
EDIT2 修复了addrlen,考虑到正在使用抽象地址空间。代码的行为保持不变。
您对addrlen
的定义有点莫名其妙。
您似乎只为地址路径保留4 + 1个字节。我想,“\ 0 | P | L | D | | \ 0”是6个字节。
sizeof(int)
来自哪里?我无法弄清楚你的意思。
但是,我认为sendto经历的原因是sendto()
和connect()
的顺序。如果在sendto之前移动连接,则会得到预期的行为。 Unix套接字缓冲数据报。在连接“开始过滤”之前,发送的数据报将通过。在交换connect和sendto的情况下,您可以看到数据报在被OS(来自发送方)接收时被过滤。当用户空间应用程序调用recv。时,似乎没有更多的过滤。
Here is an strace output (last lines only) of the modified program.
socket(PF_FILE, SOCK_DGRAM, 0) = 3
bind(3, {sa_family=AF_FILE, path=@"PLD "}, 8) = 0
socket(PF_FILE, SOCK_DGRAM, 0) = 4
bind(4, {sa_family=AF_FILE, path=@"STAR"}, 8) = 0
socket(PF_FILE, SOCK_DGRAM, 0) = 5
bind(5, {sa_family=AF_FILE, path=@"PWE0"}, 8) = 0
connect(3, {sa_family=AF_FILE, path=@"STAR"}, 8) = 0
sendto(5, "PWE0\0\0\0\n\1h\0\0\0\1\0\0\0\1", 18, 0, {sa_family=AF_FILE, path=@"PLD "}, 8) = -1 EPERM (Operation not permitted)
recvfrom(3, ^C <unfinished ...>
我改变了在函数调用中定义地址的简洁方法。这是我修改过的代码:
#include <sys/socket.h>
#include <sys/un.h>
int main()
{
const char hdr [] = "\0PLD ";
socklen_t addrlen = sizeof(sa_family_t) + sizeof(hdr);
int fd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(fd, &(struct sockaddr){ AF_UNIX, "\0PLD " }, addrlen);
int gd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(gd, &(struct sockaddr){ AF_UNIX, "\0STAR" }, addrlen);
int hd = socket(PF_UNIX, SOCK_DGRAM, 0);
bind(hd, &(struct sockaddr){ AF_UNIX, "\0PWE0" }, addrlen);
connect(fd, &(struct sockaddr){ AF_UNIX, "\0STAR" }, addrlen);
sendto(hd, "PWE0\0\0\0\n\1h\0\0\0\1\0\0\0\1", 18, 0,
&(struct sockaddr){ AF_UNIX, "\0PLD " }, addrlen);
char buf[32];
return recv(fd, buf, sizeof buf, 0);
}
我承认这有点莫名其妙。必须存在与addrlen
的{{1}}参数相关的一些未定义行为,因为如果我只将原始代码addrlen更改为sizeof(struct sockaddr_un),我会得到一个不同的行为,其中connect()是拒绝和recv阻止(也许我修改过的代码有一个我没看到的错误。)