C Unix域套接字,recvfrom()函数不会设置struct sockaddr* src_addr。

7

我正在编写一个应用程序,它在Unix域套接字上监听UDP数据包。请考虑下面的代码块。

int sockfd;
struct sockaddr_un servaddr;

sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);

if(sockfd < 0)
{
    perror("socket() failed");
}

unlink(port);

bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, port);    

if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
    perror("bind() failed");
    close(sockfd);
}

int n;
struct sockaddr_un cliaddr;
socklen_t len = sizeof(cliaddr);
discovery_msgs client_message;


bzero(&client_message, sizeof(client_message));
// Wait for a message to be received
n = recvfrom(sock_fd, &client_message, sizeof(client_message), 0, 
    (struct sockaddr *) &cliaddr, &len);

// At this point n = 560, client_message is filled with the expected data 
//len = 0 and cliaddr has no information about the client that sent the data

现在,client_message的类型并不重要,我正在接收一个UDP数据包,client_message中包含了我需要的所有数据。问题出现在我调用recvfrom后查看cliaddrlen时。与普通的网络TCP/UDP不同,recvfrom没有像平常一样修改cliaddr,而且调用后将len设置为0(这意味着recvfrom没有向&cliaddr写入任何数据)。我需要在cliaddr中填充Unix域路径的信息,以便我可以发送响应。

我做错了什么?


你可以尝试一些错误检查。socket()bind()recvfrom()返回的值是什么? - user207421
你在recvfrom()返回后立即检查了cliaddr和len吗?你在下一行设置了断点并使用了无优化构建吗?只是想知道你的调试器是否在说谎。 - Martin James
如果您希望在发送消息时附加地址,需要将套接字绑定到Unix域的端口(路径)上吗?我在Stevens的Unix编程书示例中没有看到这种情况发生。 - user2278457
嗯,也许吧。每次我使用UDP时,我都能获取到源地址。这个问题真的很烦人。这是一个好问题,OP已经做了一些调试,但我看不出有什么问题!! - Martin James
算了,看起来客户端正在绑定史蒂文斯书,并且它指出确切的原因是为了发送回复地址。哎呀。 - user2278457
显示剩余7条评论
1个回答

10
使用Unix域套接字时,解决方案是在客户端上绑定套接字。否则,在使用sendto()发送UDP数据包后立即消失的临时路径名解释了为什么服务器端无法获取客户端的地址信息。
请参阅Stevens网络编程第419页或查看此处的示例客户端实现,以解决此问题:libpix.org/unp/unixdgcli01_8c_source.html
#include    "unp.h"

int
main(int argc, char **argv)
{
    int                 sockfd;
    struct sockaddr_un  cliaddr, servaddr;

    sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0);

    bzero(&cliaddr, sizeof(cliaddr));       /* bind an address for us */
    cliaddr.sun_family = AF_LOCAL;
    strcpy(cliaddr.sun_path, tmpnam(NULL));

    Bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr));

    bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, UNIXDG_PATH);

    dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));

    exit(0);
}

注意: unp.h 定义了 Bind() 函数,它只是带有一些错误检查的 bind() 函数(通常在 Stevens 网络编程中广泛使用)。同样地,(SA *) 相当于 (struct sockaddr *)


我在我的程序中使用相同的方法。 但如果使用sock_dgram unix套接字,服务器应该如何关闭对等fd。 像udp一样不是必要的吗? - robert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接