为什么在应用程序退出后仍然存在unix-socket文件?我可以使用旧文件创建新服务器吗?

时间:2014-07-01 07:00:25

标签: c++ linux sockets unix

我开始使用unix套接字,并且首先偶然发现了打开这个新创建的文件的问题。我非常确定open()函数应该完成这项工作,但事实并非如此。我的同事说应该通过connect()函数打开一个unix套接字,所有的工作都应该像网络一样考虑。

因此,似乎我不能创建一个套接字,并退出程序(就像我一样),唯一的服务器程序应该是创建套接字的程序。但我无法理解:为什么文件系统中的套接字在程序创建者退出时不会被销毁?对我来说,这看起来肯定是一种以某种方式将应用程序连接到此套接字,并使应用程序成为服务器的方法。

下面是一个代码,仅用于说明:我执行此代码(这将创建一个名为 filename 的unix套接字),然后退出。

char* CreateSocket(const char* filename){
    if(107 <= strlen(filename)){//if the file name too long, error
        char* Buf = new char[sizeof(TOOLONGFILENAME)+sizeof(int)];
        sprintf(Buf, TOOLONGFILENAME, strlen(filename) );
        Buf[sizeof(TOOLONGFILENAME)+sizeof(int)] = 0;
        return Buf;
    }
    fdSock = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(0 > fdSock){
        char* p = strerror(errno);
        char* buf = new char[strlen(p)];
        strcpy(buf,p);
        return buf;
    }
    sockaddr_un server;
    server.sun_family = AF_UNIX;
    strcpy(server.sun_path, filename);
    if(0 > bind(fdSock, (sockaddr*)&server, sizeof(sockaddr_un))){
        char* p = strerror(errno);
        char* buf = new char[strlen(p)];
        strcpy(buf,p);
        return buf;
    }
    return 0;
}

4 个答案:

答案 0 :(得分:1)

我无法完全理解你的问题。我认为你不理解socket()机制。 我会解释。这里的套接字类似于指针或文件描述符。 有两种不同的程序:服务器和客户端。他们不依赖。服务器打开一个套接字并等待连接。客户端打开其OWN套接字,连接到远程地址。服务器处理连接。发生这两个程序之间的数据交换,然后(如果需要)终止连接。 以下是TCP / IP最简单的客户端和服务器程序的示例,它们显示了socket()机制的工作原理。

服务器代码:

void * server (void)
{
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    socklen_t lenkeepalive;
    struct net_pack recvline;
    int i,n;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(PORT);

    bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

    listen(listenfd, LISTENQ);

    int keepalive =1;
    lenkeepalive = sizeof(keepalive);
    if(setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, lenkeepalive) < 0)
    {
        perror("server: setsockopt()");
        shutdown(listenfd,SHUT_RDWR);
        close(listenfd);
        exit(EXIT_FAILURE);
    }

    pthread_create (NULL, NULL, (void *)server_send, NULL);

    for(;;)
    {

        if(connfd = accept(listenfd, (SA *) NULL, NULL)>0){
            bzero(&recvline, sizeof(recvline));
            //try get msg from connected client
            while ( (recv(connfd, &recvline, MAXLINE, 0)) > 0)
            {
                printf("server: recvline.msg - %s\n",recvline.msg);
                bzero(&recvline, sizeof(recvline));
                /*
                    ...
                */
                // send answ

                encode(&recvline,"hello2",H); //make a msg

                if(send(connfd, &recvline, (strlen(recvline.msg)+4), MSG_NOSIGNAL); < 0)
                {
                    printf("server_send: send error %d (%s)\n",errno, strerror(errno));
                }

                //discard client connection
                shutdown(connfd,SHUT_RDWR);
                close(connfd);
            }

        }

    }

    // some error occurs    
    perror("server: accept()");
    shutdown(listenfd,SHUT_RDWR);
    close(listenfd);
    return 0;
}

客户端代码

void * client (void)
{
    socklen_t           lenkeepalive;
    int                 sockfd, keepalive, n;
    struct net_pack recvline;       //pack for msg 
    struct sockaddr_in  servaddr;

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {printf("client: socket error %d ( %s )\n ",errno, strerror(errno));}

    keepalive = 1;
    lenkeepalive = sizeof(keepalive);
    if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, lenkeepalive) < 0)
    {
        perror("client: setsockopt()");
        shutdown(sockfd,SHUT_RDWR);
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(PORT);

    if (inet_pton(AF_INET, servip, &servaddr.sin_addr) <= 0)
        printf("client: inet_pton error for %s\r\n", servip);


    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        printf("client: connect to %s error %d ( %s )\r\n",servip, errno, strerror(errno));
    }
    else
    {
        // send a msg

        encode(&recvline,"hello",H); //make a msg

        n = send(sockfd, &recvline, (strlen(recvline.msg)+4), MSG_NOSIGNAL);
        if(n < 0)
        {printf("client: i cannot send, error %d (%s)\n",errno, strerror(errno));}

        bzero(&recvline, sizeof(recvline));

        //recv data from server
        while( (n = recv(sockfd, &recvline, MAXLINE, 0)) >= 0)
            {
                printf("client: recvline.msg - %s\n",recvline.msg);
                bzero(&recvline, sizeof(recvline));
            }
    }

    // some error occurs
    perror("client: recv()");
    shutdown(sockfd,SHUT_RDWR);
    close(sockfd);

    return 0;
}

在你的情况下,你应该使用sockaddr_un而不是sockaddr_in,以及一些必要的标志,如AF_UNIXSOCK_DGRAM和其他。

答案 1 :(得分:1)

W的绝妙书“套接字网络API:UNIX®网络编程第1卷,第三版” 中的短引用。理查德·史蒂文斯;比尔·芬纳Andrew M. Rudoff

第15章。示例:Unix域套接字的绑定。

  

首先删除路径名。我们绑定到套接字的路径名是命令行参数。但是,如果文件系统中已存在路径名,则绑定将失败。因此,如果路径名已经存在,我们调用unlink删除该路径名。如果不存在,则取消链接将返回错误,我们将忽略该错误。

实际上,您可以使用该路径来检测服务器是否存在。服务器终止时,必须删除文件以使客户端了解没有服务器可以读取传入的连接。例如, Docker 就是这样工作的:如果没有生成守护程序,则系统中没有docker.sock文件。

答案 2 :(得分:0)

要充当面向连接的服务器,应用程序会创建一个套接字,然后绑定,然后侦听以获取传入连接。

然后,对于每个传入连接,应用程序接受并为其提供服务。

每项操作都有一项功能:socketbindlistenaccept

此处必须执行所有步骤,并且所有步骤都必须在同一应用程序中执行。你不能创建一个绑定套接字,然后让其他程序使用它。

面向连接的客户端需要创建一个套接字,然后调用connect

面向数据报的通信没有连接,不使用listenacceptconnect

答案 3 :(得分:0)

我没有研究实际的理由,但是我可以假设的是套接字API本身并不关心文件。

您可以将其与通过IP连接进行比较。您绑定到端口,然后断开连接,但是该端口始终存在,并且永远不会被删除。

对于UNIX套接字,创建不存在的文件是有意义的(尽管我不认为套接字API本身会创建文件,而是请求其使用,然后在文件上自动创建文件-也许操作系统),但是从API的角度来看,删除该文件没有工作,只是不再使用它。