我正在尝试修改原始的 Michael Kerrisk的 AF_UNIX SOCK_DGRAM示例客户端/服务器程序。请单击以下两个链接(clientserver)以获取更多信息。该示例代码最初发表在他的书 The Linux Programming Interface,第57章中。我的目标是根据 Kerrisk的代码示例,用“抽象套接字”定义替换“文件套接字”定义。

不幸的是,我无法在客户端和服务器的版本之间建立通信。当然, Kerrisk的版本适用于色彩艳丽的

对我来说很明显,我做的事情根本上是错误的……但是……我不知道这是什么。

===================服务器============================== ==

这是我对'server'的Kerrisk代码的版本:

int main(int argc, char *argv[])
{
   struct sockaddr_un svaddr, claddr;
   int sfd, j;
   ssize_t numBytes;
   socklen_t len;
   char buf[BUF_SIZE];

   char *abstract_server;

   sfd = socket(AF_UNIX, SOCK_DGRAM, 0);       /* Create server socket */
   if (sfd == -1)
       errExit("socket");

   abstract_server = "viper_server";
   /* Construct well-known address and bind server socket to it */

   if (remove(abstract_server) == -1 && errno != ENOENT)
       errExit("remove-%s", abstract_server);

   memset(&svaddr, 0, sizeof(struct sockaddr_un));
   svaddr.sun_family = AF_UNIX;
   strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));

   if (bind(sfd, (struct sockaddr *) &svaddr,
     sizeof(sa_family_t) + strlen(abstract_server) + 1) == -1)
       errExit("bind");

   /* Receive messages, convert to uppercase, and return to client */

   for (;;) {
       len = sizeof(struct sockaddr_un);
       numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
                           (struct sockaddr *) &claddr, &len);
       if (numBytes == -1)
           errExit("recvfrom");

       printf("Server received %ld bytes from %s\n", (long) numBytes,
               claddr.sun_path);

       for (j = 0; j < numBytes; j++)
       buf[j] = toupper((unsigned char) buf[j]);

       if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) != numBytes)
           fatal("sendto");
     }
 }

=======================客户======================= =====

这是我对'client'的Kerrisk代码的版本:
int main(int argc, char *argv[])
{
    struct sockaddr_un svaddr, claddr;
    int sfd, j;
    size_t msgLen;
    ssize_t numBytes;
    char resp[BUF_SIZE];

    char *abstract_client;
    char *abstract_server;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s msg...\n", argv[0]);

    /* Create client socket; bind to unique pathname (based on PID) */

    sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sfd == -1)
        errExit("socket");

    abstract_client = "viper_client";
    abstract_server = "viper_server";

    memset(&claddr, 0, sizeof(struct sockaddr_un));
    claddr.sun_family = AF_UNIX;
    strncpy(&claddr.sun_path[1], abstract_client, strlen(abstract_client));

    if (bind(sfd, (struct sockaddr *) &claddr,
      sizeof(sa_family_t) + strlen(abstract_client) + 1) == -1)
        errExit("bind");

    /* Construct address of server */

    memset(&svaddr, 0, sizeof(struct sockaddr_un));
    svaddr.sun_family = AF_UNIX;
    strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));

    /* Send messages to server; echo responses on stdout */

    for (j = 1; j < argc; j++) {
        msgLen = strlen(argv[j]);       /* May be longer than BUF_SIZE */

       /* code FIX */
       if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                 (sizeof(sa_family_t) + strlen(abstract_server) + 1) ) != msgLen)
              fatal("sendto");

        /* original - non working code - replaced with the code FIX above
        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                sizeof(struct sockaddr_un)) != msgLen)
        {
            fatal("sendto");
        } */

        numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, NULL, NULL);
        /* Or equivalently: numBytes = recv(sfd, resp, BUF_SIZE, 0);
                        or: numBytes = read(sfd, resp, BUF_SIZE); */
        if (numBytes == -1)
            errExit("recvfrom");
        printf("Response %d: %.*s\n", j, (int) numBytes, resp);
    }

    remove(claddr.sun_path);            /* Remove client socket pathname */
    exit(EXIT_SUCCESS);
}

我如何启动测试:
> ./server &
> ./client  aa bb cc
> result:  ERROR: sendto

任何帮助|建议|解决方案RTFM非常受欢迎

伊戈尔

P.S.由于我的声誉不到10,因此我只能发布2个链接(请参阅这篇文章顶部的Kerrisk的客户URL,Kerrrisk的服务器URL)。因此,我对“如何使用抽象套接字”的 Kerrisk的 C代码片段进行了“剪切和粘贴”。它发表在他的书中,第1176页, list 57-8。
int main(int argc, char *argv[])
{
    int sockfd;
    struct sockaddr_un addr;
    char *str;

    memset(&addr, 0, sizeof(struct sockaddr_un));  /* Clear address structure */
    addr.sun_family = AF_UNIX;                     /* UNIX domain address */

    /* addr.sun_path[0] has already been set to 0 by memset() */

    str = "xyz";        /* Abstract name is "\0abc" */
    strncpy(&addr.sun_path[1], str, strlen(str));

    // In early printings of the book, the above two lines were instead:
    //
    // strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) - 2);
    //            /* Abstract name is "xyz" followed by null bytes */

    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1)
        errExit("socket");

    if (bind(sockfd, (struct sockaddr *) &addr,
            sizeof(sa_family_t) + strlen(str) + 1) == -1)
        errExit("bind");

    // In early printings of the book, the final part of the bind() call
    // above was instead:
    //        sizeof(struct sockaddr_un)) == -1)

    sleep(60);

    exit(EXIT_SUCCESS);
}

最佳答案

您的服务器绑定(bind)的地址与客户端在sendto()中使用的地址不同。这是因为您在客户端和服务器中计算svaddr的长度的方式有所不同。

服务器:sizeof(sa_family_t) + strlen(abstract_server) + 1)
客户:sizeof(struct sockaddr_un)
Unix套接字地址是struct sockaddr_un.sun_path中描述的路径的整个给定长度。更改大小计算后,以匹配客户端和服务器工作。

编辑 s/abstract_client/abstract_server/似乎我的复制和粘贴错误与其他答案相同。

关于c - 将 'abstract sockets'与AF_UNIX SOCK_DGRAM一起使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18711996/

10-12 18:41