2014-12-06 130 views
2

我假設對於只有1字節(字符)的消息,我將直接使用read()和write()。通過套接字發送和接收字符串的子函數

對於那些大小大於1字節的消息,我使用兩個子函數來讀寫套接字。

例如,我有服務器構造一個名爲strcities(城市列表)的字符串並將其打印出來 - >沒有什麼奇怪的。然後將該字符串的字節數發送到客戶端,然後發送實際的字符串。

客戶端首先會讀取字節數,然後是實際的城市列表。

出於某種原因,我的代碼有時可以工作,有時不會。如果它有效,它還會打印出一些額外的字符,我不知道它們來自哪裏。如果沒有,它會掛起並永遠在客戶端等待,而服務器則返回到循環的頂部並等待來自客戶端的下一個命令。你能否看看我的代碼下面,讓我知道我做錯了什麼?

Attempt_read

string attempt_read(int rbytes) { // rbytes = number of bytes of message to be read 
    int count1, bytes_read; 
    char buffer[rbytes+1]; 
    bool notdone = true; 

    count1 = read(sd, buffer, rbytes); 

    while (notdone) { 
     if (count1 == -1){ 
      perror("Error on write call"); 
      exit(1); 
     } 
     else if (count1 < rbytes) { 
      rbytes = rbytes - count1; // update remaining bytes to be read   
      count1 = read(sd, buffer, rbytes); 
     } 
     else {notdone = false;} 
    }  // end while 
    string returnme; 
    returnme = string(buffer); 
    return returnme; 
} 

Attempt_write

void attempt_write(string input1, int wbytes) { // wbytes = number of bytes of message 
    int count1; 
    bool notdone = true; 

    count1 = write(sd, input1.c_str(), wbytes); 

    while (notdone) { 
     if (count1 == -1){ 
      perror("Error on write call"); 
      exit(1); 
     } 
     else if (count1 < wbytes) {  
      wbytes = wbytes - count1; 
      count1 = write(sd, input1.c_str(), wbytes);  
     }   
     else {notdone = false;} 
    } // end while 
    return; 
} 
+0

嗯,我確實編寫和編譯的C++代碼,以便這就是爲什麼我想我添加了標籤C++ – rustyengineer 2014-12-06 16:57:20

+0

這是一個項目的分配和選擇是C,C++和Java。我們選擇C++ – rustyengineer 2014-12-06 17:02:44

+0

是的,我們很清楚這一點。但我想這就是我們選擇的,所以我們必須繼續它 – rustyengineer 2014-12-06 17:05:32

回答

1

1)串類有一個方法大小(),將返回字符串的長度,所以你實際上並不需要第二個attempt_write參數。

2)你可以在消息前傳送消息的長度,或者你可以在傳送一個終止0之後,如果你只發送一個ASCII字符串。由於您的連接可能隨時終止,因此最好在發送字符串之前發送準確的長度,以便您的客戶知道,期望什麼。 3)你使用什麼編譯器,這將允許字符緩衝區[rbytes + 1]; ?標準的C++需要char buffer = new char [rbytes + 1];並進行相應的刪除以避免內存泄漏。

4)在您的代碼中,第二次讀取函數調用使用相同的緩衝區而不調整長度,所以您實際上會覆蓋已接收的數據,並且只有在所有數據都將以第一個函數呼叫。這同樣適用於寫功能

我建議是這樣的:

void data_read(unsigned char * buffer, int size) { 
    int readed, total = 0; 

    do { 
    readed = read(sd, buffer + total, size - total); 
    if (-1 == writted) { 
     perror("Error on read call"); 
      exit(1); 
     } 

    total += readed; 
    } while (total < size); 
} 

string attempt_read() { 
    int size = 0; 
    data_read((unsigned char *) &size, sizeof(int)); 

    string output(size, (char) 0x0); 

    data_read((unsigned char *) output.c_str(), size); 

    return output; 
} 

void data_write(unsigned char * buffer, int size) { 
    int writted, total = 0; 

    do { 
    writted = write(sd, buffer + total, size - total); 
    if (-1 == writted) { 
     perror("Error on write call"); 
      exit(1); 
     } 

    total += writted; 
    } while (total < size); 
} 

void attempt_write(string input) { 
    int size = input.size();  
    data_write((unsigned char *) &size, sizeof(int)); 
    data_write((unsigned char *) input.c_str(), size); 
} 
+0

感謝您的回覆! 1.我注意到,謝謝! 2.我認爲這就是我一直在使用我的代碼。首先發送消息的大小,然後發送實際消息 3.我不確定你在問什麼? 4.我讀了閱讀手冊頁http://linux.die.net/man/2/read,它說:「成功時,讀取的字節數被返回(零表示文件結束),並且文件位置被這個數字提前「。所以我假設對於attempt_read()我不需要更新緩衝區的位置? – rustyengineer 2014-12-06 16:56:38

+0

不,文件位置是您讀取的文件設備。您仍然需要調整自己的緩衝區位置。至於「char buffer [rbytes + 1];」標準C++不會允許它,如果你試圖編譯這樣的代碼,你應該會收到一個錯誤。靜態數組是在編譯時分配的,所以它的長度需要先知道。如果你想要動態數組,你需要使用new []和delete []操作符或std :: vecor,或者在文本消息的情況下使用std :: string。不,你的代碼沒有發送消息的大小,你發送的所有內容都是一個字符串。 – Dmitry 2014-12-06 23:20:25

+0

Idk爲什麼但由於某種原因,我沒有得到char buf [rbytes + 1]的編譯錯誤?我將它編譯在UNIX服務器上。是的,我想我沒有在我的帖子中明確提到,在主函數中,我對這個attempt_write/attempt_read進行了2次調用,第一次發送/接收消息的大小,第二次調用將發送/接收實際的消息。 – rustyengineer 2014-12-08 02:55:42