2017-02-23 76 views
0

試圖創建一個管道,可以關閉一串隨機數。分裂成父母和小孩,產生隨機數字,如果孩子寫信給管道,如果是父母讀書。我覺得這很接近,但我的輸出是無稽之談。有人可以解釋一下管道的作用,並告訴我如何執行這個動作的方向是正確的。與字符串數組一起使用管道

#include <sys/types.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <iostream>   /* c++ I/O headers */ 
#include <string.h> 
#include<math.h> 

using namespace std; 

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

//Get the number of random numbers 
int numberOfRandomNumbers = stoi(argv[1]); 

//char childPipe[200], parentPipe[200]; //pipes to hold numbers 
int pid, index, count; //counters 
int pipe1[2]; // main pipe 

int xyz = pipe(pipe1); //perform the pipe 
string stringOfRandomNumbers = ""; 

pid = fork(); //fork the process 

//check for errors------------------------------------------- 
if(xyz < 0 || pid < 0){ 
    //break 
    cout << "Error" << endl; 
    return 0; 
} 

//Check process---------------------------------------------- 

if (pid == 0) { /* child */ 

    srand(pid+4); //seed the random 
    int randNum; 


    //Start building the string 
    stringOfRandomNumbers = "Child, ID = "; 
    stringOfRandomNumbers += to_string(pid); 
    stringOfRandomNumbers += ", Random numbers: >"; 


    //Now generate random numbers 
    for (index = 0; index < numberOfRandomNumbers; index++) { 

     randNum = rand() % 100; 

     //add to string..... 
     if(index == (numberOfRandomNumbers - 1)){ 
      //last one 
      stringOfRandomNumbers += (to_string(randNum) + "<"); 
     } 
     else{  

      stringOfRandomNumbers = stringOfRandomNumbers + (to_string(randNum) + ", "); 

     } 

    } 

    cout << endl << stringOfRandomNumbers << " length = " << stringOfRandomNumbers.length() << endl; 

    close(pipe1[0]); //don't read off of pipe 
    write(pipe1[1], stringOfRandomNumbers, stringOfRandomNumbers.length()); 
    close(pipe1[1]); //done 

} 

else {  /* parent */ 


    // Now generate random numbers 
    srand(pid+8); 
    int randNum; 

    //Start the string 
    stringOfRandomNumbers = "Parent, ID = "; 
    stringOfRandomNumbers += to_string(pid); 
    stringOfRandomNumbers += ", Random numbers: >"; 


    //Now generate random numbers 
    for (index = 0; index < numberOfRandomNumbers; index++) { 

     randNum = rand() % 100; 

     //Add to string..... 
     if(index == (numberOfRandomNumbers - 1)){ 
      //last one 
      stringOfRandomNumbers += (to_string(randNum) + "<"); 
     } 
     else{  

      stringOfRandomNumbers = stringOfRandomNumbers + (to_string(randNum) + ", "); 
     } 
    } 

    close (pipe1[1]); 

    count = read(pipe1[0], stringOfRandomNumbers, stringOfRandomNumbers.length()); 

    for (index=0; index < count; index++){ 
      cout << stringOfRandomNumbers[index] << endl; 
    } 
    close (pipe1[0]); //done 
} 
} 
+0

此外,任何額外的材料,這個問題將不勝感激。 – MattCucco

+0

你爲什麼在父母身上產生隨機數字?當你在父進行讀取調用時,你應該提供一個緩衝區和最大長度讀入緩衝區。 –

+0

查看閱讀電話的文檔。我不相信它允許'std :: string'作爲參數傳遞。 –

回答

2

readwrite是老派的C函數。他們不知道C++字符串是什麼,並且假定stringOfRandomNumbers是指向要發送的數據或希望接收的緩衝區的指針。

stringOfRandomNumbers不是一個指針,你應該從編譯器那裏得到一個警告信息,如果不是完全拒絕編譯的話。即使它是一個指針,std::string也不一定直接包含它所表示的數據。通常情況下,std::string指向一個動態分配的存儲塊,如果您使用writestd::string,則寫入指針而不是指向的數據。

接收std::string現在有一個指向存儲器的指針,在發送過程中有意義,但在接收過程中是沒有意義的或危險的。如果兩者都在同一個進程中,那麼內存仍然有效,但是您有兩個指向同一內存的std::string。只要std::string中的一個超出範圍,它將刪除內存並使其他std::string指向無效內存。

兩種方式都很糟糕。

接下來,因爲你會被髮送std::string對象,而不是字符串數據那將是愚蠢的運氣,如果字符串數據的長度完全匹配的sizeof(std::string)所以無論是垃圾數據或者沒有足夠的數據將被髮送。

你想要做的是沿着

write(pipe1[1], stringOfRandomNumbers.c_str(), stringOfRandomNumbers.length()+1); 

std::string::c_str線的東西得到一個指向包含字符串數據的緩衝區,而+1發送緩衝區的終止空,以便接收器知道在哪裏該字符串停止。

這種方法給你帶來一個問題:我需要讀多少數據?您必須繼續閱讀管道,並將讀取的內容附加到std::string,直到找到空。噁心的樣子。

但是

uint32_t len = stringOfRandomNumbers.length(); 
write(pipe1[1], &len, sizeof(len)); 
write(pipe1[1], stringOfRandomNumbers.c_str(), len); 

寫入字符串首先作爲一個32位無符號整數的長度,然後從緩衝stringOfRandomNumbers寫入len字節。

警告:uint32_t是可選的,可能不被編譯器支持。我們的想法是確保兩臺PC確切知道長度有多大,因此您可能必須找到發送方和接收方都同意的固定大小。

在接收側,

uint32_t len; 
read(pipe1[0], &len, sizeof(len)); //read len 
std::vector<char> buffer(len+1); // Make buffer big enough for string and terminating null 
read(pipe1[0], buffer.data(), len); // read into buffer 
buffer[len] = '\0'; // null terminate 
stringOfRandomNumbers = buffer.data(); 

的C++ 17標準投影到使這一點更容易,因爲你將能夠從一個std::string請求非const數據指針。提前確定std::string的大小,您可以安全地直接讀取它。

+0

在一個管道的上下文中,兩個進程在同一臺機器上(一個是另一個的分支副本,天啊!),所以像'int'這樣的實現定義的類型將會很好。在網絡環境中,您可能希望使用htonl/ntohl。 –

+0

實際上,您可以調整讀取字符串的大小,然後傳遞'&stringOfRandomNumbers [0]'.today。事實上,我*認爲*保證今天工作。 –

+0

神聖的愚蠢愚蠢的剪貼錯誤!謝謝,馬丁。 – user4581301

相關問題