使用 Unix 域套接字进行电话对话的 IPC 机制

Posted

技术标签:

【中文标题】使用 Unix 域套接字进行电话对话的 IPC 机制【英文标题】:IPC mechanism for telephone conversation using Unix domain sockets 【发布时间】:2014-03-18 21:09:10 【问题描述】:

我正在为电话对话实现 IPC。创建了两个文件:receiver.c 和 caller.c.. rc.h 包含所有包含文件。我正在根据 FIFO 的 .. 测试 Unix 域套接字的使用。 caller.c 文件是:

#include "rc.h"
int main()

    int sock_fd;
    struct sockaddr_un unix_addr;
    char buf[2048];
    int n;
    if ((sock_fd=socket(AF_UNIX,SOCK_STREAM,0))<0)
    
        perror("cli:socket()");
        exit(1);
    
    unix_addr.sun_family=AF_UNIX;
    strcpy(unix_addr.sun_path,SERVER);
    if (connect(sock_fd,(struct sockaddr *) &unix_addr,
        sizeof(unix_addr.sun_family)+
        sizeof(unix_addr.sun_path))< 0)
    
        perror("cli:connect()");
        exit(1);
    
    sprintf(buf,"Reciever called by receiver");
    n=strlen(buf)+1;
    if (write (sock_fd,buf,n)!=n)
    
        perror("cli:write()");
        exit(1);
    
    printf("Caller sent-->%s",buf);
    if ((n=read(sock_fd,buf,2047))<0)
    
        perror("cli:read()");
        exit(1);
    
    buf[n]=0;
    while (buf[n]==0)n--;
    if (buf[n]=='\n')
        buf[n]='\0';
    printf("Reciever received<--%s \n",buf);
    exit(0);

receiver.c 是:

#include <signal.h>
#include "rc.h"

static void stop(int n)

    unlink(SERVER);
    exit(0);


static void receiver()

    int sock_fd,cli_sock_fd;
    struct sockaddr_un unix_addr;
    char buf[2048];
    int n,addr_len;
    pid_t pid;
    char *pc;

    signal(SIGINT,stop);
    signal(SIGQUIT,stop);
    signal(SIGTERM,stop);
    unix_addr.sun_family=AF_UNIX;
    strcpy(unix_addr.sun_path,SERVER);
    addr_len=sizeof(unix_addr.sun_family)+strlen(unix_addr.sun_path);
    unlink(SERVER);
    if (bind(sock_fd,(struct sockaddr *)&unix_addr,addr_len)<0)
    
        perror("Receiver:bind()");
        exit(1);
    
    if (listen(sock_fd,5)<0)
    
        perror("Receiver:caller()");
        unlink(SERVER);
        exit(1);
    
    while ((cli_sock_fd=accept(sock_fd,(struct sockaddr*)&unix_addr,&addr_len))>=0)
    
        if ((n=read(cli_sock_fd,buf,2047))<0)
        
            perror("Receiver:read()");
            close(cli_sock_fd);
            continue;
        
        buf[n]='\0';
        for(pc=buf;*pc!='\0' && (*pc<'0' || *pc>'9');pc++);
        pid=atol(pc);
        if (pid!=0)
        
            sprintf(buf,"Receiver called by caller\n",pid);
            n=strlen(buf)+1;
            if (write(cli_sock_fd,buf,n)!=n)
                perror("Receiver:write()");
        
        close(cli_sock_fd);
    
    perror("Receiver:accept()");
    unlink(SERVER);
    exit(1);


int main()

    int r;
    if ((r=fork())==0)
        receiver();
    if(r<0)
    
        perror("Receiver:fork()");
        exit(1);
    
    exit(0);

现在在编译时出现问题:

sourajyoti@ubuntu:~/os2$ gcc receiver.c -o test1
receiver.c: In function ‘stop’:
receiver.c:6:9: warning: unknown escape sequence: '\s' [enabled by default]
receiver.c: In function ‘receiver’:
receiver.c:23:28: warning: unknown escape sequence: '\s' [enabled by default]
receiver.c:25:9: warning: unknown escape sequence: '\s' [enabled by default]
receiver.c:34:10: warning: unknown escape sequence: '\s' [enabled by default]    
receiver.c:58:9: warning: unknown escape sequence: '\s' [enabled by default]

然后在这之后:

sourajyoti@ubuntu:~/os2$ ./test1
Receiver:bind(): Bad file descriptor

客户端也一样:

sourajyoti@ubuntu:~/os2$ gcc caller.c -o test2    
caller.c: In function ‘main’:    
caller.c:15:28: warning: unknown escape sequence: '\s' [enabled by default]    
sourajyoti@ubuntu:~/os2$ ./test2    
cli:connect(): No such file or directory

头文件rc.h为:

     #include <sys/types.h>
     #include <sys/socket.h>
     #include <sys/un.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>
     #include <stdio.h>
     #include <errno.h>
     #include <stdlib.h>
     #include <unistd.h>
     #define SERVER "\tmp\server"

【问题讨论】:

pat 回答了你,但我有一个很好的使用 /temp 的解决方案,使用 mktemp functionman 3 mktemp 你能详细说明一下吗?我是新手.. \s 我已经设法改变了。但是绑定仍然是一个问题。我不明白为什么套接字无法创建?? 你把SERVER改成了什么?您是否在接收器中添加了对socket() 的呼叫? 【参考方案1】:

我已经说过,pat 回答了你,但我说的是使用mktemp

       char sfn[15] = "";
       FILE *sfp;

       strlcpy(sfn, "/tmp/ed.XXXXXX", sizeof sfn);
       if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) 
               fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
               return (NULL);
       
       return (sfp);

应该这样改写:

       char sfn[15] = "";
       FILE *sfp;
       int fd = -1;

       strlcpy(sfn, "/tmp/ed.XXXXXX", sizeof sfn);
       if ((fd = mkstemp(sfn)) == -1 ||
           (sfp = fdopen(fd, "w+")) == NULL) 
               if (fd != -1) 
                       unlink(sfn);
                       close(fd);
               
               fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
               return (NULL);
       
       return (sfp);

【讨论】:

目标是创建一个客户端和服务器都知道的名称的 UNIX 域套接字。此代码创建一个文件,其名称只有该程序知道。 pat,我之前说过,我只是想帮助如何使用/temp,如果你想使用write socket daemon,请将socket与daemon分开。谷歌如何编写守护进程,我建议:netzmafia.de/skripten/unix/linux-daemon-howto.html,并阅读更多关于 TCP 或 UDP 的信息,因为我不了解你的项目,有些项目需要 UDP,有些需要 TCP。 为您的套接字用户 POSIX therad ,命名为 ptherad【参考方案2】:

您的 SERVER 宏具有非法的 '\s' 转义序列。不幸的是,您没有显示标题的内容,所以我看不到定义。

您的接收器实际上并没有创建套接字。它只是绑定了一个未初始化的sock_fd,导致它失败。

客户端失败,因为接收方从未创建过它可以连接的套接字。

编辑

好的,现在我可以看到SERVER 的定义,我看到您在路径名中使用了反斜杠而不是正斜杠。

在receiver中,你还需要创建一个socket,代码和client类似:

if ((sock_fd=socket(AF_UNIX,SOCK_STREAM,0))<0)

    perror("Receiver:socket()");
    exit(1);

通常,当我bind一个UNIX域套接字时,我只是给sizeof(unix_addr)作为地址长度:

if (bind(sock_fd,(struct sockaddr *)&unix_addr,sizeof(unix_addr))<0)

    perror("Receiver:bind()");
    exit(1);

【讨论】:

我已经上传了rc.h文件。 \s 我已经设法改变了。但是绑定仍然是一个问题。我不明白为什么套接字无法创建??

以上是关于使用 Unix 域套接字进行电话对话的 IPC 机制的主要内容,如果未能解决你的问题,请参考以下文章

IPC Unix 域套接字 bash

进程间通信(IPC)——Unix域套接字 VS 网络套接字

《Unix 网络编程》15:Unix 域协议

UNIX域套接字

UNIX域协议(命名套接字)

使用 node-ipc 和 unix 套接字在 C 和 NodeJS 之间进行通信