2012-10-14 31 views
1

我正在TCP中構建一個基本的客戶端和服務器。它的工作除非密鑰變得很大。它只是發送來回鍵直到時間結束。當它變得更大(aka 4096)時,read()語句將隨機得到一個null值,然後將該關鍵字分解爲兩個消息,然後中斷循環。read()函數中的隨機空字符

我真的不確定它爲什麼這樣做,服務器代碼正在工作,因爲它已經與其他客戶端進行了測試,所以我的客戶端出了問題。任何想法(這是很短):

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 

#define BUFFER_LENGTH 5120 

// Error message taken from reference 
void error(const char *msg) 
{ 
    printf("%s\n", msg); 
    exit(0); 
} 
int main(int argc, char *argv[]) 
{ 
    int sockfd, portNumber, n; 
    struct sockaddr_in serv_addr; 
    struct hostent *server; 

    // Invalid arguments 
    if (argc < 4) 
     exit(0); 
    else if (atoi(argv[3]) < 1 || atoi(argv[3]) > 4096) 
     exit(0); 

    char buffer[BUFFER_LENGTH]; 
    bzero(buffer, BUFFER_LENGTH); 
    char buffer2[BUFFER_LENGTH]; 
    bzero(buffer2, BUFFER_LENGTH); 
    strcpy(buffer2, "Connect. Key length: "); 
    strcpy(buffer, strcat(buffer2, argv[3])); 
    portNumber = atoi(argv[2]); // Get port number in int format 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); // Create socket connection to server using internet constants 

    // Did we open the socket succesfully? 
    if (sockfd < 0) 
     error("Error opening socket."); 

    // Is the IP Address valid? 
    server = gethostbyname(argv[1]); 
    if (server == NULL) 
     error("Could not connect to server. Terminating."); 

    // Initialize to zero and then set 
    // Taken from reference 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); 
    serv_addr.sin_port = htons(portNumber); 
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
     error("Could not connect to server. Terminating."); 

    short connected = 1; 
    do 
    { 
     // Send initial request on first pass 
     // Afterwards send the resposne we were given 
     printf("Sending: %s\n", buffer); 
     printf("Length of msg: %d\n", (strlen(buffer) + 1)); 
     n = write(sockfd, buffer, strlen(buffer) + 1); 
     if (n < 1) 
      error("Failed to send Message. Terminating."); 

     // Get session key response 
     bzero(buffer, BUFFER_LENGTH); 
     n = read(sockfd, buffer, BUFFER_LENGTH); 
     if (n < 1) 
      error("Could not fetch result. Terminating."); 

     // Stop 
     if (strcmp(buffer, "Invalid session key. Terminating.") == 0) 
      break; 

     printf("%s\n", buffer); 
     sleep(1); 
    } while (connected == 1); 

    // Done (this should never be reached in this client) 
    error("Could not fetch result. Terminating."); 
    close(sockfd); 
    return 0; 
} 
+0

我應該能夠告訴服務器正在發送什麼?預計它是一個有效的字符串? (中間沒有空值) – altendky

+0

服務器預計將與「會話密鑰:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX」響應(其中X是隨機的字符,其中多達4096) – MasterGberry

+2

和'讀取結果()'告訴你有多少個字符讀。 @altendky:'NULL'是一個空*指針*常量;使用它來引用空字符/字節是不正確的。 –

回答

5

請勿在二進制數據上使用strcpy()或任何str*()函數。你沒有處理字符串。使用memcpy()並指定要複製的字節數。

str*()功能操作字符串;一個字符串被C標準定義爲「由第一個空字符終止並且包括第一個空字符的連續字符序列」。但是在二進制數據中,空字符(零字節)只是另一個數據塊,不一定具有任何意義。

如果你的二進制數據看起來像這樣(十六進制):

4b d9 e7 b3 00 96 89 fb 

然後strcpy()會忽略00字節後的一切。更糟的是,如果你的二進制數據是這樣的:

4b d9 e7 b3 2f 96 89 fb 

沒有空字節,然後strcpy(),或strlen(),或任何字符串函數將繼續過去的緩衝區的末尾,有不可預知的結果。

+0

的'strlen的()'調用指定寫的長度好像一個實際上是有問題的。 – altendky

+0

Errrr,我似乎已經沒有任何問題,直到我進入while循環,然後在任何地方從2到呼叫的X數量將持續,直到它隨機未接受,因爲空字符的整個味精崩潰。它似乎適用於2048年和以下,所以我一直在想這是一個緩衝區問題,但似乎並非如此 – MasterGberry

+0

您正在緩衝區中使用字符串函數可能不包含任何空字符 - 如果確實如此,它們不會標記數據的邏輯結尾。使用'mem *()'函數,*不使用'str *()'函數。 –

-1

僅用於調試,也許是sleep()將是write()read()之間有幫助,從而給服務器的時間來應對呢?配置適當的超時將是長期處理它的正確方法。再一次,我可能會完全錯誤的軌道上。

+1

睡覺*從不*在網絡編程的幫助。讀取()會阻塞,直到收到數據。睡覺實際上是浪費時間。 – EJP

+0

同意,'睡眠()'是明顯錯誤的事情,雖然用於調試時間問題有用。 'read()'保證讀取指定的字節數?或只是爲了阻止,直到它看到了什麼?不知何故,我沒有找到明確的參考。 – altendky

1

您假設一個write()發送的數據恰好被一個read()讀取。 TCP或Sockets API規範中沒有任何內容支持這種假設。您必須閱讀,直到您收到完整的消息,並且「消息」由您定義,而不是由TCP或API定義。