最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Splicing standard input to a socket - Stack Overflow

programmeradmin3浏览0评论

As part of a larger program, I would like to copy everything from standard input to a UNIX domain socket. I figured that splice(2) would likely be appropriate but I'm having trouble using it.

Minimal Example

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <fcntl.h>

int main(void) {
    int sock;
    struct sockaddr_un addr;
    const char *socket_path = "/tmp/test.sock";

    int exit_status = EXIT_SUCCESS;

    if (socket_path == NULL) {
        exit(EXIT_FAILURE);
    }

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }

    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);

    if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
        perror("connect");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }

    ssize_t bytes_spliced;
    /* I'm setting the offsets to NULL because they don't make sense in pipes or sockets */
    while ((bytes_spliced = splice(STDIN_FILENO, NULL, sock, NULL, 16384, SPLICE_F_MORE)) > 0) {
    }

    if (bytes_spliced == -1) {
        perror("splice");
        exit_status = EXIT_FAILURE;
    }

cleanup:
    close(sock);
    return exit_status;
}

All I get is:

splice: Invalid argument

As part of a larger program, I would like to copy everything from standard input to a UNIX domain socket. I figured that splice(2) would likely be appropriate but I'm having trouble using it.

Minimal Example

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <fcntl.h>

int main(void) {
    int sock;
    struct sockaddr_un addr;
    const char *socket_path = "/tmp/test.sock";

    int exit_status = EXIT_SUCCESS;

    if (socket_path == NULL) {
        exit(EXIT_FAILURE);
    }

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }

    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);

    if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
        perror("connect");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }

    ssize_t bytes_spliced;
    /* I'm setting the offsets to NULL because they don't make sense in pipes or sockets */
    while ((bytes_spliced = splice(STDIN_FILENO, NULL, sock, NULL, 16384, SPLICE_F_MORE)) > 0) {
    }

    if (bytes_spliced == -1) {
        perror("splice");
        exit_status = EXIT_FAILURE;
    }

cleanup:
    close(sock);
    return exit_status;
}

All I get is:

splice: Invalid argument
Share Improve this question asked Feb 16 at 17:27 Runxi YuRunxi Yu 3432 silver badges9 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

The problem is that standard input is not always a pipe, and splice(2) requires at least one side to be a pipe.

$ ./test < test.c
splice: Invalid argument
(exit: 1)
$ cat test.c | ./test
$ ./test
(exit: 1)

In the first case, standard input is a file, which cannot be spliced. In the second case, it is a pipe. In the third case, it's a character device i.e. my terminal.

发布评论

评论列表(0)

  1. 暂无评论