2009-05-21 64 views
1

我有兩個簡單的程序設置,通過unix域套接字共享數據。一個程序從隊列中讀取數據並將其發送到其他應用程序。在發送之前,每段數據的前面加上四個字節的長度,如果小於四個字節,則剩下的字節是'^'符號。unix域流套接字發送更多的數據,那麼它應該是

客戶端應用程序然後讀取前四個字節,將緩衝區設置爲適當的大小,然後讀取其餘的。我遇到的問題是第一次通過郵件將被完美髮送。在此之後的每隔一段時間,都會發送額外的數據,因此會出現諸如「多麼美好的一天」之類的消息,如「多麼美好的一天?X?」。所以我覺得像一個緩衝區沒有被正確清除,但我似乎無法找到它。

客戶端代碼:

listen(sock, 5); 
for (;;) 
{ 
    msgsock = accept(sock, 0, 0); 
    if (msgsock == -1) 
     perror("accept"); 
    else do 
    { 
     char buf[4]; 
     bzero(buf, sizeof(buf)); 
     if ((rval = read(msgsock, buf, 4)) < 0) 
     perror("reading stream message"); 

     printf("--!%s\n", buf); 

     string temp = buf; 
     int pos = temp.find("^"); 
     if(pos != string::npos) 
     { 
      temp = temp.substr(0, pos); 
     } 

     int sizeOfString = atoi(temp.c_str()); 
     cout << "TEMP STRING: " << temp << endl; 
     cout << "LENGTH " << sizeOfString << endl; 
     char feedWord[sizeOfString]; 
     bzero(feedWord, sizeof(feedWord)); 

     if ((rval = read(msgsock, feedWord, sizeOfString)) < 0) 
       perror("reading stream message"); 

      else if (rval == 0) 
       printf("Ending connection\n"); 
      else 
       printf("-->%s\n", feedWord); 
       bzero(feedWord, sizeof(feedWord)); 
       sizeOfString = 0; 
       temp.clear(); 
     } 
     while (rval > 0); 
     close(msgsock); 
    } 
    close(sock); 
    unlink(NAME); 

服務器代碼

   pthread_mutex_lock(&mylock); 
       string s; 
       s.clear(); 
       s = dataQueue.front(); 
       dataQueue.pop(); 
       pthread_mutex_unlock(&mylock); 

       int sizeOfString = strlen(s.c_str()); 
       char sizeofStringBuffer[10]; 

       sprintf(sizeofStringBuffer, "%i", sizeOfString); 
       string actualString = sizeofStringBuffer; 
       int tempSize = strlen(sizeofStringBuffer); 

       int remainder = 4 - tempSize; 
       int x; 
       for(x =0; x < remainder; x++) 
       { 
        actualString = actualString + "^"; 
       } 

       cout << "LENGTH OF ACTUAL STRING: " << sizeOfString << endl; 

       actualString = actualString + s; 

       cout << "************************" << actualString << endl; 
       int length = strlen(actualString.c_str()); 

       char finalString[length]; 
       bzero(finalString, sizeof(finalString)); 
       strcpy(finalString, actualString.c_str()); 

          if (write(sock, finalString, length) < 0) 
          perror("writing on stream socket");  

回答

2

,而不是 '^' 填充你的數據包長度,你會好得多隻是在做:

snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString); 

,以便值爲0填充 - 然後您不需要解析出接收器中的'^'字符代碼。

另請編輯您的調試代碼 - 當前代碼中只有一個write(),並且與您的協議描述不符。

理想情況下 - 將你的發送例程分解成它自己的函數。您還可以利用writev()來處理將持有「length」字段的字符串與保存實際數據的緩衝區合併,然後將其作爲單個原子發送給write()

未經測試的代碼如下:

int write_message(int s, std::string msg) 
{ 
    struct iovec iov[2]; 
    char hdr[5]; 

    char *cmsg = msg.c_str(); 
    int len = msg.length(); 

    snprintf(hdr, 5, "%04d", len); // nb: assumes len <= 9999; 

    iov[0].iov_base = hdr; 
    iov[0].iov_len = 4; 

    iov[1].iov_base = cmsg; 
    iov[1].iov_len = len; 

    return writev(s, iov, 2); 
} 
+0

這看起來像是一個很好的解決方案,但我對readv如何處理有些困惑。在閱讀方面,我只是將一個緩衝區設置爲iov [0]的大小。iov_len然後用iov [1] .iov_base填充該緩衝區? – whatWhat 2009-05-22 22:50:40

2

你必須同時檢查writeread的返回值不僅-1但對於短(小於請求)寫入/讀取。你似乎只是在perror打印錯誤後才繼續 - 做一個exit(2)什麼的。

0

兩件事情:

第一 - 在服務器端,你寫了你的數組的末尾。

char finalString[length]; 
bzero(finalString, sizeof(finalString)); 
strcpy(finalString, actualString.c_str()); 

strcpy()length+1字符複製到finalString(字符拉空終止)。

其次(也可能是問題) - 在客戶端,您不是null,會終止您讀入的字符串,因此printf()將打印您的字符串,然後是堆棧中的任何內容,直到它命中null。

增加兩個緩衝區一個,你應該是更好的形狀。