尝试将数据从子进程服务器传送到其父进程

问题描述:

我正在为分布式系统类进行分配。我是C.S.的硕士生,但我在编程方面的专长是.NET,我正在开发一个需要一些相当参与的Unix知识的项目,这让我感到沮丧。尝试将数据从子进程服务器传送到其父进程

该任务正在实施刷新通道协议API。所以我正在编写一个小函数库,其他应用程序可以实现使用刷新通道通信。我已经设置好了,所以当init函数被调用时,它会派生一个子进程来充当传入消息的服务器。通过管道将传入数据发送给父级,子级与父级进程通信。

如果一次发送和接收一条消息,则可以正常工作;例如,

发送 - >接收 - >发送 - >接收 - >等

然而,如果多个消息在做任何接收之前发送;例如,

发送 - >发送 - >发送 - >收到

然后它就会搞砸。特别是,第一条消息被正确接收,但是当我去接收第二条消息时,程序挂起并需要被终止。我在网上做了很多搜索,并且在这个数小时之内一直在堵塞,但还没有取得很大的进展。

该程序整体来说太大而不能在这里显示,但这里是最相关的位。这是我得到服务器并接收消息的部分。注意行

write(fd [1],buffer,(strlen(buffer)+1));

- 我认为这是一个很好的候选人,可以成为问题的根源,但不知道该做什么不同。 (尝试的fwrite()和未在所有的工作。)

fd = malloc(2 * sizeof(int)); 
    int nbytes; 
    if (pipe(fd) < 0) { 
     perror("Could not create pipe"); 
     return -1; 
    } 

    pID = fork(); 

    if (pID < 0) { 
     perror("Failed to fork"); 
     return -1; 
    } else if (pID == 0) { // child 
     close(fd[0]); // close input side of pipe 
     int cc; 
     int fsize; 
     struct sockaddr_in from; 
     int serials[500]; 
     int i; 
     for (i = 0; i < 500; i++) serials[i] = 0; 

     char buffer[2048]; 

     while (1) { 
      fsize = sizeof(from); 
      cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize); 
      if (cc < 0) perror("Receive error"); 
      datagram data = decodeDatagram(buffer); 
      if (serials[data.serial] == 0) { 
       write(fd[1], buffer, (strlen(buffer)+1)); 
       serials[data.serial] = 1; 
      } 
     } 
    } else { // parent 
     close(fd[1]); // close output side of pipe 
     return 0; 
    } 

(其中“连续”阵列为不转发重复的消息,因为消息被发送多次,以提高可靠性。我知道的固定大小对于这个数组是不好的做法,但因此它在这方面确定此任务测试不发送很多消息)

接收功能的开头是这样的:

int fRecv(int* id, char* buf, int nbytes) { 

    checkDatagramTable(*id); 

    char* tbuf = malloc((nbytes + 9) * sizeof(char)); 
    int rbytes = read(fd[0], tbuf, nbytes + 9); 

“+9”用于容纳随附的附加信息要发送的消息,用于刷新频道排序。这也是一个非常粗略的领域,但分配更多的空间是非常有用的,这并没有帮助解决问题。

我知道这里有很多无关的东西,对其他函数的引用等。但问题肯定在于我如何通过管道传输数据,所以我的问题的来源应该在某处。

在此先感谢您的帮助;这是真正的赞赏。

+0

你分配通过'而(1)'循环一个新的'buffer'每一次旅行 - - 为什么?我不明白为什么它是动态分配的而不是堆栈分配的,我不明白为什么它会在这个函数之外持续存在。 – sarnold

+0

顺便说一句,'strace(1)'在尝试追查问题时非常有用。这就像每个系统调用的免费的'printf(3)'行。 – sarnold

+0

我不记得我为什么那样做,但显然有一个很好的理由,因为将它改为堆栈分配会导致编译器给出一些非常不祥的警告。为什么?你认为这与我遇到的问题有关吗? – user1056100

这看起来很可疑。 (包中有什么?它们可能是二进制的)数据报的类型定义在哪里?

fsize = sizeof(from); 
     cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize); 
     if (cc < 0) perror("Receive error"); 
     datagram data = decodeDatagram(buffer); 
     if (serials[data.serial] == 0) { 
      write(fd[1], buffer, (strlen(buffer)+1)); // <-- ???? 
      serials[data.serial] = 1; 
     } 

我想尝试,而不是:

  write(fd[1], buffer, cc); 

UPDATE:

如果消息没有空终止,你必须明确地终止它:

(if cc == 2048) cc -= 1; 
    buffer [cc] = '\0'; // <<-- 
    datagram data = decodedatagram(buffer); 
    ... 

此外,建议使用“sizeof buffer”而不是“2048”。

UPDATE2: 你可以测试是否在包中的字符串真的空值终止:

 unsigned pos; 
     cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize); 
     if (cc < 0) perror("Receive error"); 
     for pos=0; pos < cc; pos++) { 
      if (buff[pos] == 0) break; 
      } 
     switch (cc-pos) { 
     case 0: fprintf (stderr, "No nul byte found in packet: I lose!\n"); break; 
     default: fprintf (stderr, "Spurious nul byte found in the middle of packet\n"); 
     case 1: break; 
      } 

     datagram data = decodeDatagram(buffer); 
     if (serials[data.serial] == 0) { 
      write(fd[1], buffer, cc); 
      serials[data.serial] = 1; 
     } 
+0

数据包保证是字符数据;这是作业描述的一部分 - 对不起,我应该在我的问题中指出这一点。在任何情况下,在改变它之后,它的行为都是一样的 - 在顺序发送和接收数据时工作正常,但是当用户应用程序接收数据包之前一次发送一组数据包时,它会在尝试检索时挂起第二个数据包。 – user1056100

+0

他们可能是角色,但他们是空终止?发送者是否明确地在每个数据包的末尾放置'\ 0'?此外:如果你知道数据包是空终止的,为什么*会*调用strlen()? – wildplasser

+0

这些都是好点,但正如我所说,我改变了你的建议,并没有改变行为。 – user1056100