c中的数据报套接字。看起来父进程永远不会绑定

Posted

技术标签:

【中文标题】c中的数据报套接字。看起来父进程永远不会绑定【英文标题】:datagram sockets in c. looks like parent process never binds 【发布时间】:2014-06-10 17:08:35 【问题描述】:

我尝试执行以下两个进程的代码。 孩子发送一个数据报,父母应该接收并打印它 .父进程看起来没有绑定(错误:地址已在使用中)。 有什么想法吗?

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

#define N 9

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

int pid,s,n,addrlen; 
char msg[N]; 
struct sockaddr_un addr;

addr.sun_family=AF_UNIX;        
strcpy(addr.sun_path,"test-socket");    // pathname
addrlen=sizeof(addr.sun_family)+strlen(addr.sun_path);

if (!(pid=fork())) 
    printf("child\n");
    s=socket(PF_UNIX,SOCK_DGRAM,0); 
    sleep(3); /* wait for parent to bind */

    sendto(s,"hi parent",9,0,(struct sockaddr*)&addr,addrlen);  
    printf("child sent\n");
    close(s);

    return(0);

printf("father\n");
s=socket(PF_UNIX,SOCK_DGRAM,0);
bind(s,(struct sockaddr *)&addr,addrlen);   // error here

n=recvfrom(s,msg,N,0,NULL,NULL);        
if(n<=0)printf("error\n");
msg[n]='\0'; printf("%s\n",msg);
close(s);
unlink("test-socket");              

return(0);

【问题讨论】:

您看起来正在将 9 个字节接收到一个 9 字节缓冲区中,然后在缓冲区末尾 (msg[n]) 后以空终止一个字节。你能纠正一下,然后再试一次吗? 您不检查来自socketbindsendto 的返回值。这样做 - 并在记录错误时使用errno/strerror - 看看你是否忽略了问题。 绑定命令返回错误:地址已在使用中 【参考方案1】:

为什么不在fork之前绑定呢?等待固定的时间然后发送数据不是一个好主意

【讨论】:

尝试在 fork 之前创建套接字并绑定..没有工作【参考方案2】:

在我的系统上(Mac OS X Snow Leopard)sockaddr_un 看起来像这样:

struct  sockaddr_un 
        unsigned char   sun_len;        /* sockaddr len including null */
        sa_family_t     sun_family;     /* [XSI] AF_UNIX */
        char            sun_path[104];  /* [XSI] path name (gag) */
;

假设您的看起来类似,您对 addrlen (sizeof(addr.sun_family)+strlen(addr.sun_path)) 的计算是错误的,这将导致使用它的调用 sendtobind 使用与您认为正在使用的路径不同的路径– 它将被截断。

您对bind 的调用可能正在创建一个名为test-socke 的套接字文件(请注意末尾缺少的t)。当您的程序完成时,它会尝试unlink 不存在的文件test-socket。这意味着下次您运行程序时,您尝试将 bind 转换为 (test-socke) 的文件已经存在,因此 bind 将以您看到的方式失败。

要解决此问题,您需要确保为 addrlen 使用正确的长度。最简单最安全的方法大概就是使用sizeof(addr)

addrlen = sizeoff(addr);

如果可用,您也可以使用SUN_LEN,如果您担心,这可能会节省您复制几个字节的时间:

addrlen = SUN_LEN(&addr);

如果您想自己计算正确的长度(例如 SUN_LEN 不可用),请尝试以下操作:

addrlen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path);

(这是改编自我系统上SUN_LEN的定义。)

【讨论】:

以上是关于c中的数据报套接字。看起来父进程永远不会绑定的主要内容,如果未能解决你的问题,请参考以下文章

AMQP 连接丢失不会杀死父进程,因此永远不会发生重新连接

fork()和僵尸进程

C中进程间通信中的数据流控制[关闭]

进程管理

子进程 c 的返回值

python多进程和多线程