如果使用Ctrl + c关闭客户端,服务器将在"send"中死亡

Zag*_*rax 4 c sockets send

我无法理解为什么这个应用程序死了send.这是服务器的代码:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <stdlib.h>
#include <errno.h>

#define UNIX_PATH_MAX    108
#define SPATH "./sock"

int main() {
    int sfd, rv = 100, newfd;
    char b[100];
    char ok[3] = "ok\0";
    struct sockaddr_un sa;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);

    strncpy(sa.sun_path, SPATH, UNIX_PATH_MAX);
    sa.sun_family = AF_UNIX;

    if (bind(sfd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    if (listen(sfd, SOMAXCONN) == -1) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    if ((newfd = accept(sfd, NULL, NULL)) == -1) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    while (rv != -1 && rv != 0) {
        rv = recv(newfd, b, 100, 0);

        printf("%s\n", b);

        sleep(3);

        printf("Send reply\n");
        send(newfd, ok, 3, 0);
        printf("Sent reply\n");
    }

    printf("END\n");
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果客户端在Ctrl+C发送消息后立即强制关闭,则服务器将打印(作为最后一行):

before send

然后它会在没有做任何事情的情况下死去 我试图检查errno或其他任何东西(包括sendif语句中的调用),但似乎它send本身导致服务器死亡.我尝试过write但是它是一样的.

我用bash检查了它的返回码,并以退货代码141退出,我无法理解它的含义.

如果你想尝试,这是客户端代码:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#define UNIX_PATH_MAX    108
#define SPATH "./sock"

int main() {
    int sfd, rv;
    char b[100];
    char ok[3];
    struct sockaddr_un sa;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);

    strncpy(sa.sun_path, SPATH, UNIX_PATH_MAX);
    sa.sun_family = AF_UNIX;

    connect(sfd, (struct sockaddr*)&sa, sizeof(sa));

    while (scanf("%s", b)) {
        send(sfd, b, 100, 0);

        recv(sfd, ok, 3, 0);

        printf("%s\n", ok);
    }

    printf("END\n");
}
Run Code Online (Sandbox Code Playgroud)

只需编译两个,运行两个,然后在发送消息后立即使用Ctrl + C终止客户端.

jxh*_*jxh 12

当您呼叫send()已经关闭的连接时,操作系统可能会SIGPIPE向您的进程发出问题.通常默认的处理程序SIGPIPE是杀死你的进程.

为了防止这种情况发生,您可以忽略信号(例如,使用signal(SIGPIPE, SIG_IGN)sigignore(SIGPIPE)),或者您可以将MSG_NOSIGNAL选项传递给send():

int send_result = send(newfd, ok, 3, MSG_NOSIGNAL);
if (send_result >= 0) {
    /* okay, but check if all your data got sent! */
    if (send_result < 3) /* ...do something */;
} else {
    switch (errno) {
    /* ... */
    case EPIPE:
        /* sending on a closed connection... */
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,呼叫将失败,而不是发出SIGPIPE,将被设置为.send()errnoEPIPE

  • 你读得不够远.`EPIPE`包含在5.13中. (2认同)