2011-11-20 78 views
2

我正在爲分佈式系統類進行分配。我是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

回答

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; 
     } 

我想嘗試,而不是:

  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

相關問題