2013-07-05 109 views
0

我在寫兩個程序時遇到了一些問題,服務器和客戶端。爲了保持簡單和時間順序,我首先寫了服務器並用telnet和netcat測試了它,並且一切正常(除了read()/ recv()的返回值不同之外,因爲它看起來像正常的telnet程序在要發送的字符串末尾添加一個額外的字符,但無論如何...)。c套接字 - 沒有收到所有發送的數據

現在我也編寫了客戶端程序,但是我沒有獲得其他兩個客戶端正確接收的所有數據,特別是我從MySQL查詢中獲得的行[i]字符串。當每次send()函數引入usleet()調用並正確接收所有數據時,情況就會改變。

現在我正在考慮不兼容的緩衝區大小問題(?),但在玩了一段時間並檢查了尺寸之後,我無法找到任何東西。

你會發現下面的代碼,如果你有任何建議請不要猶豫告訴我。

TNX

/*客戶代碼*/

#define BUFSIZE 1000 
... 
void *send_handler(void *); 
... 
int main(int argc, char *argv[]) { 
    char buf[BUFSIZE]; 
    ... 
    socket stuff... 
    ... 
    connect 
    ... 
    /* receive string from server - working */ 
    bzero(buf, BUFSIZE); 
    n = read(sockfd, buf, BUFSIZE); 
    if (n < 0) 
     error("ERROR reading from socket"); 
    buf[n] = '\0'; 
    printf("%s", buf); 
    ... 
    /* send username to server - working */ 
    bzero(buf, BUFSIZE); 
    fgets(buf, BUFSIZE, stdin); 
    n = write(sockfd, buf, strlen(buf)); 
    if (n < 0) 
     error("ERROR writing to socket"); 
    ... 
    /* start receiving handler */ 
    if(pthread_create(&thread_id , NULL , send_handler , (void*) &sockfd) < 0) { 
    perror("could not create thread"); 
     return 1; 
    } 

    /* main thread for reading data */ 
    while(1) { 
     bzero(buf, BUFSIZE); 
     n = read(sockfd, buf, BUFSIZE); 
     if (n < 0) 
    error("ERROR reading from socket"); 
    buf[n] = '\0'; 
    printf("%s", buf); 
    } 

    close(sockfd); 
    return 0; 
} 

void *send_handler(void *socket_desc) { 
    //Get the socket descriptor 
    int sock = *(int*)socket_desc; 
    char buf[BUFSIZE]; 
    int n; 

    while (1) { 
     bzero(buf, BUFSIZE); 
     fgets(buf, BUFSIZE, stdin); 
     n = write(sock, buf, strlen(buf)); 
     if (n < 0) 
      error("ERROR writing to socket"); 
    } 
} 

/*服務器代碼*/

void *connection_handler(void *); 

int main(int argc , char *argv[]) { 
    ... 
    /* socket variables */ 
    ... 
    pthread_t thread_id; 
    ... 
    socket stuff... 
    ... 
    while((client_sock = accept(socket_desc, (struct sockaddr *)&client_addr, (socklen_t*)&client_len))) { 
     if(pthread_create(&thread_id , NULL , connection_handler , (void*) &client_sock) < 0) { 
     perror("could not create thread"); 
      return 1; 
    } 
    } 
    return 0; 
} 

void *connection_handler(void *socket_desc) { 
//Get the socket descriptor 
int sock = *(int*)socket_desc; 
    ... 
    /* mysql variables */ 
char cmd[1000]; 
... 
MYSQL_RES *result; 
MYSQL_ROW row; 
MYSQL *con; 
... 
/* connection variables */ 
int read_size, i; 
char *message; 
char client_message[2000]; 
char buffer[1000]; 
    ... 
    //clear the buffers 
memset(client_message, '\0', 2000); 
    ... 
    snprintf(cmd, 999, "SELECT field1, field2, field3, field4 FROM files WHERE key='%s' ORDER BY id DESC", var); 
if (mysql_query(con, cmd)) { 
    error checks... 
} 
result = mysql_store_result(con); 
if (result == NULL) { 
    error checks... 
} 
else { 
    num_rows = mysql_num_rows(result); 
} 
if (num_rows == 0) { 
    message = "Nothing found\n"; 
    send(sock , message , strlen(message), 0); 
} 
    else { 
    num_fields = mysql_num_fields(result); 
    num_rows = mysql_num_rows(result); 
     snprintf(buffer, 999, "Number of rows: %d\n", num_rows); 
    send(sock , buffer , sizeof(buffer), 0); 
    //usleep(10000); // commented, but necessary to work properly... 
     memset(buffer, '\0', sizeof(buffer)); 

     while ((row = mysql_fetch_row(result))) { 
    for(i = 0; i < num_fields; i++) { 
     snprintf(buffer, 999, "%s\t", row[i] ? row[i] : "NULL"); 
     send(sock , buffer , sizeof(buffer), 0); 
     //usleep(10000); 
     memset(buffer, '\0', sizeof(buffer)); 
     } 
     message = "\n"; 
     send(sock , message , strlen(message), 0); 
     //usleep(10000); 
    } 
    message = "\n"; 
    send(sock , message , strlen(message), 0); 
     //usleep(10000); 
    mysql_free_result(result); 
} 
... 
} 

編輯:我改變 的printf( 「%S」,BUF);

與 printf(「Bytes read:%d \ n」,n); 在客戶端代碼和我獲得以下輸出:

帶有註釋usleep()函式:

Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 36 
Bytes read: 1000 
Bytes read: 31 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 2 
(17 lines) 

與usleep(0)減慢發送流程(獲得正確的輸出):

Bytes read: 1000 
Bytes read: 33 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1 
Bytes read: 1 
Bytes read: 1000 
Bytes read: 31 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1000 
Bytes read: 1 
Bytes read: 1 
(21 lines) 

任何提示?

解決:只需用

strlen(buffer); 
在服務器部分

更換

sizeof(buffer); 

,一切工作正常,即使沒有usleep()函式,輸出正確/完整。

無論如何。

+0

無法看到你的init套接字,它們是否可以被阻塞? – fghj

+0

而不能看到你如何處理「沒有找到」類型的消息,例如你發送沒有發現,然後1000字節的結果,在客戶端你收到「沒有找到」+ 1000 - 「找不到」字節,下一次調用閱讀返回發送的其餘部分。 – fghj

+0

我沒有設置任何非阻止選項,所以我假定默認阻止行爲。對於什麼也沒有找到的消息,它工作正常,但也許有1000個字節的錯誤,因爲我嗅探了迴環流量,似乎所有的數據都是由服務器發送的(這與telnet一致和netcat輸出),但客戶端無法全部捕獲它 –

回答

1

您的代碼中存在爭用條件,您將一個指向局部變量的指針傳遞給線程函數。由於filedescriptor(int)不大於void指針(我敢肯定,這是保證,但添加一個斷言儘管如此),您還可以將描述符轉換爲指針,而不是傳遞本地地址filedescriptor:

int s = accept(...); 
if(int e = pthread_create(.., &connection_handler, (void*)s, ..)) 
    error(..); 

BTW:pthread_create在成功時返回零,否則返回一個錯誤代碼,這不是負數。但是在那時你的代碼不太可能失敗。

4

您不能假設單個讀取讀取整個消息。 TCP中沒有消息,只有字節,並且任何給定的讀取可能只返回一個字節,或者同時在對等體上幾次寫入的結果。你必須循環和解析。

+0

您能否提供一個代碼示例或如何更改我的代碼的相關部分? Tnx –

+0

@angelobarilla當然,你可以寫一個循環沒有進一步的幫助? – EJP

相關問題