【问题标题】:unix domain socket programmingUnix域套接字编程
【发布时间】:2014-06-02 12:52:37
【问题描述】:

我有一个unix域套接字程序,客户端尝试连接服务器并发送消息,当服务器接受客户端并读取消息时,它将休眠5秒并发送另一条消息。在5秒内如果我使用 ctrl+c 杀死客户端,那么服务器将退出。我该如何处理这种情况?我的程序如下:

客户:

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>

#define INFO_SERVER_PATH "/var/info_server_path"


int create_route_client()
{
    int client_fd;
    int addr_len;

    struct sockaddr_un server_addr;

    if ((client_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
        perror("create route info client socket");
        return -1;
    }

    memset(&server_addr, 0, sizeof(struct sockaddr_un));
    server_addr.sun_family = AF_LOCAL;
    strcpy(server_addr.sun_path, INFO_SERVER_PATH);
    addr_len = offsetof(struct sockaddr_un,sun_path) + strlen(server_addr.sun_path);

    if (connect(client_fd, (struct sockaddr*)&server_addr, addr_len) < 0) {
        perror("socket connect");
        return -1;
    }

    return client_fd;
}


int main(int argc, char const *argv[])
{

    char *sendline = "hello server";
    char recvline[512];
    int client_fd;
    int nwrite;
    int nread;

    client_fd = create_route_client();
    assert(client_fd > 0);

    nwrite = write(client_fd, sendline, strlen(sendline));
    if (nwrite < 0) {
        perror("failed to send command to the info server");
        close(client_fd);
        return 1;
    }

    nread = read(client_fd, recvline, sizeof(recvline));
    if (nread < 0) {
        perror("failed to read route state");
        close(client_fd);
        return 1;
    }
    recvline[nread] = '\0';
    printf("%s\n", recvline);
    close(client_fd);

    return 0;
}

服务器:

#include <unistd.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <string.h>
 #include <assert.h>
 #include <stddef.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdint.h>

 #define INFO_SERVER_PATH "/var/info_server_path"
 int create_command_server()
 {
    struct sockaddr_un server_addr;
    size_t addr_len;
    int server_fd;

    if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("create socket");
        return -1;
    }
    unlink(INFO_SERVER_PATH);

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strcpy(server_addr.sun_path, INFO_SERVER_PATH);
    addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(INFO_SERVER_PATH);

    if (bind(server_fd, (struct sockaddr*)&server_addr, addr_len) < 0) {
        perror("socket bind");
        return -1;
    }

    if (listen(server_fd, 1) < 0) {
        perror("socket listen");
        return -1;
    }

    return server_fd;
}

int main(int argc, char const *argv[])
{
    int info_server_fd = create_command_server();
    char recvline[512];
    char *sendline = "hello client";
    int nread;
    int nwrite;

    while (1) {
        int info_client_fd = accept(info_server_fd, NULL, NULL);
        nread = read(info_client_fd, recvline, 512);

        if (nread) {
            int i;
            for (i = 0; i < 5; i++) {
                printf("i = %d\n", i);
                sleep(1);
            }
            nwrite = write(info_client_fd , sendline, strlen(sendline));
            printf("nwrite = %d\n", nwrite);
            if (nwrite < 0) 
                perror("failed to send to client");

        }
        close(info_client_fd);
    }


    return 0;
}

【问题讨论】:

  • 这段代码中没有'sleep for 5 seconds'。也没有任何东西会导致服务器退出。在接受的套接字上也没有任何适当的错误检查或流结束检查。从您的问题中不清楚是服务器还是客户端应该休眠,也不清楚您所描述的是您想要发生的事情还是您不想要的已经发生的事情。
  • 您需要提供更多信息。当您说“退出”时,它究竟是因为什么而退出的? SIGPIPE?
  • to EJP:这就是我曾经让服务器休眠 5 秒 for (i = 0; i
  • to caskey: 'quits' 表示服务器进程退出,它应该在 while(1) 循环中永远运行以接受客户端并发送回消息
  • 所以你已经解决了我的六个问题之一。

标签: c sockets unix network-programming unix-socket


【解决方案1】:

如果不编译和运行您的代码,很难准确判断,但我猜您会收到一个 SIGPIPE 信号,因为您写入了在您杀死客户端时关闭的连接。接收 SIGPIPE 的进程的默认操作是终止该进程。

您可以使用 sigprocmask() 阻止 SIGPIPE 信号,或者告诉内核您想要阻止它、忽略它或使用 sigaction() 为它注册一个异步信号处理程序。然后,当您调用 write() 时,它将返回 -1 并且 errno 将设置为 EPIPE。请参阅 write() http://man7.org/linux/man-pages/man2/write.2.html 的手册页。

有关信号以及如何处理它们的更多信息,请参见信号 http://man7.org/linux/man-pages/man7/signal.7.html 的手册页。但是,请注意,除非您非常小心并且确切地知道自己在做什么,否则不应使用异步信号处理程序来处理信号。这是许多错误的根源。如果您不需要它们,或者阻止它们并使用同步信号处理方法,如 sigwait() 或信号 fd(Linux 特定),则最安全(到目前为止)忽略它们是最安全的。在您的情况下,您不需要它们。 write() 调用会告诉你连接何时消失。

【讨论】:

    猜你喜欢
    • 2015-07-20
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多