2012-10-02 204 views
3

可能重複:
What is the correct way of reading from a TCP socket in C/C++?如何發送和接收數據的TCP套接字(C/C++)

我試圖建立一個TCP客戶端/服務器。我的問題是,當我嘗試從客戶端發送數據時,我會在發送的數據中執行此操作。

但我的問題出現時,當我嘗試接收具有特定結構的數據,我的意思是,前8個字節設置日期,下10個名稱和未定義的字節數設置文本(本文結尾/ R/N/R/N)

客戶端發送如下:

char date[8]; 
char name[10]; 
char msg[4096]; 

strcpy(msg,"12/10/12"); //8 bytes 
strcat(msg,"Kevin Fire"); //10 bytes 
strcat(msg,"abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde\r\n\r\n"); 

nbytes_sent = send(sock,(char *)msg,sizeof(msg),0); 
printf("Bytes_sent: %s -> %i\n",msg,nbytes_sent); 

並且服務器嘗試從插座分析數據如下:

char date[8]; 
char name[10]; 
char * text; 
char buf[1024]; 

int i=0; 
for(i=0; i < 8; i++) 
    date[i] = '\0'; 
for(i=0; i < 10; i++) 
    name[i] = '\0'; 

nbytes_read=recv(sclient,(char *)date,sizeof(date),0); 
if(nbytes_read > 0){ 
    printf("Date: %s (%i)\n",date,nbytes_read); 
    //cout.flush(); 
    nbytes_read=recv(sclient,(char *)name,sizeof(name),0); 
    if(nbytes_read > 0){ 
     printf("Name: %s (%i)\n",name,nbytes_read); 
     //cout.flush(); 
     nbytes_read=recv(sclient,(char *)buf,sizeof(buf),0); 
     strcpy(text,buf); 
     while(nbytes_read > 0){ 
      nbytes_read=recv(sclient(char*)buf,sizeof(buf),0); 
      strcat(text,buf); 
     } 
    } 
} 

printf("Date: %s. Name: %s. Text: %s\n",date,name,text); 
+0

讓我猜猜,一個或所有的'recv'電話不回你問的具體數額?或者您打印的字符串沒有正確終止? –

+0

不要僅僅標記一切在你腦袋裏飛馳而過的東西。對UDP進行標記絕對沒有任何理由,除非有非常明確的標記兩者的理由,否則應該標記C或C++。 – Wug

+0

這應該是C或C++(用*標記*) – WhozCraig

回答

1

一個(重複)錯誤是:

nbytes_read=recv(sclient,(char *)date,sizeof(date),0); 

recv()不爲空終止。這意味着如果讀取字節,date將不會有空終止符。當一個非空終止的字符串作爲參數傳遞給printf()並使用"%s"格式說明符時,這是一個問題。如果字符串非空終止,則可能會在實際的字符串數據之後看到垃圾字符。你需要閱讀比目標緩衝區少了一個和空終止或使用格式說明"%*.s"不需要空終止:

printf("%.*s", n, s); /* Prints first 'n' bytes from 's'. */ 

注意,你可以初始化一個char[]所有空值,而不是使用for的:

char date[8] = ""; 

或者您可以使用memset()

1

添加到@ hmjd的發現:

在VAR decls宣稱是你的文本指針...

char * text; 

再後來......

strcpy(text,buf); 
while(nbytes_read > 0){ 
    nbytes_read=recv(sclient(char*)buf,sizeof(buf),0); 
    strcat(text,buf); 
} 

也許嘗試設置,「文本'指向除了隨機堆棧值之外的東西也會有幫助。

繼續攻勢,雖然下面不一定會炸掉,你date變量:

char date[8]; 

在客戶端和服務器端,客戶端變量不使用的。然而,服務器變量是:

nbytes_read=recv(sclient,(char *)date,sizeof(date),0); 
if(nbytes_read > 0){ 

問題是,您發送的日期實際上是8個字符寬:「12/10/12」。因此,即使你的固件更新一空終結你的字符串,你應該總是做不管(好習慣)的結尾:

date[ sizeof(date)/sizeof(date[0])-1 ] = 0; 

你會被截斷了你日期的最後一個字符。

這還有其他的錯誤;我們只指出了一些。考慮使用數組中的每個數據值發送長度前綴,並使用檢查或範圍來確保獲得預期的結果。最後,花一些時間在調試器的業務端可能會很好,尤其是在服務器端。

+0

+1錯過了,可能是OP正在經歷的問題。 – hmjd

5

下面是一個簡單的「接受所有」功能:

int recv_all(int sockfd, void *buf, size_t len, int flags) 
{ 
    size_t toread = len; 
    char *bufptr = (char*) buf; 

    while (toread > 0) 
    { 
     ssize_t rsz = recv(sockfd, bufptr, toread, flags); 
     if (rsz <= 0) 
      return rsz; /* Error or other end closed cnnection */ 

     toread -= rsz; /* Read less next time */ 
     bufptr += rsz; /* Next buffer position to read into */ 
    } 

    return len; 
}