2012-05-03 54 views
0

我遇到了一次只在客戶端接收一行的問題。我正在嘗試通過一種方式一次接收整個流。任何人都可以糾正我對接收問題的看法嗎?我已經包含了客戶端代碼和一部分我認爲是相關的服務器端代碼。c socket編程,一次只接收一行

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


int main(int argc, char *argv[]) 

{ 
    FILE *log; 
    int opt; 
    int count = 0; 
    int sock, bytes_received; 
    char send_data[2048],recv_data[2048]; 
    struct hostent *host; 
    struct sockaddr_in server_addr; 

    if(remove("client_log")) ; 

    if(argc == 2) 
    { 
     if(strcmp(argv[1], "-v") == 0) 
     { 
     log = fopen("client_log", "a"); 
     opt = 1; 
     } 
     else if(strcmp(argv[1], "-V") == 0) 
     { 
     log = fopen("client_log", "a"); 
     opt = 2; 
     } 
    } 

    } 
    else 
     opt = 0; 

    host = gethostbyname("127.0.0.0"); 

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 
     perror("Socket"); 
     exit(1); 
    } 

    server_addr.sin_family = AF_INET; 
    server_addr.sin_port = htons(noneya); 
    server_addr.sin_addr = *((struct in_addr *)host->h_addr); 
    bzero(&(server_addr.sin_zero),8); 

    if (connect(sock, (struct sockaddr *)&server_addr, 
       sizeof(struct sockaddr)) == -1) 
    { 
     perror("Connect"); 
     exit(1); 
    } 

    while(1) 
    { 

     bytes_received=recv(sock,recv_data,2048,0); 
     recv_data[bytes_received] = '\0'; 

     if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0) 
     { 
     close(sock); 
     break; 
     } 

     else 
     { 
     if(opt != 0) 
      fprintf(log, "\n Received Data: %s \n", recv_data); 
     if(opt == 2) 
      printf("\nReceived Data: %s \n" , recv_data); 
     } 

     if(count == 0) 
     { 
     printf("Pick an option: \n"); 
     printf("1 - to search by Department only\n"); 
     printf("2 - to search by Department and Class Number\n"); 
     printf("3 - to search more specifically\n"); 
     printf("q or Q - to Quit"); 
     } 
     printf("\nSEND: "); 
     gets(send_data); 
     if(count == 0) 
     { 
     count = (int)send_data; 
     if(count == 3) 
      count++; 
     } 
     else if(count > 0) 
     count--; 

     if(opt != 0) 
      fprintf(log, "\n Sending Data: %s \n", send_data); 
     if(opt == 2) 
      printf("\n Sending Data: %s \n" , send_data); 

     if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0) 
     send(sock,send_data,strlen(send_data), 0); 

     else 
     { 
     send(sock,send_data,strlen(send_data), 0); 
     close(sock); 
     break; 
     } 

    } 
return 0; 
} 

這是事物的客戶端:

case 1: 

      fread(data, sizeof(sched_record), MAX_RECORD, filePointer); 
      fclose(filePointer); 
      char send_data[] = "Enter Department Name"; 
      send(connected, send_data, strlen(send_data), 0); 
      bytes_received = recv(connected, recv_data, BUF, 0); 
      recv_data[bytes_received] = '\0'; 
      strcpy(tempDept, recv_data); 
      for (i=0; i<MAX_RECORD; i++){ 
       if ((strcmp(tempDept, data[i].Dept)==0) && tempCourse != data[i].course){ 
         sprintf(send_data,"%s %d", data[i].Dept, data[i].course); 
         send(connected, send_data, strlen(send_data), 0); 
         tempCourse = data[i].course; 

       } 
      } 
     break; 

,如果需要,我可以提供更多的信息。我相信服務器方面沒問題。我已經編譯了-Wall和-Wextra,並沒有收到任何警告。

回答

3

您一次接收數據一行,因爲它一次發送一行。然而,它最終以這種方式出現的事實是純粹的運氣; TCP流可以被客戶端TCP棧任意分割和重組,或者通過另一端緩衝。在流中需要某種形式的顯式幀,例如,在每行之前發送一個計數,或者在一行的末尾輸入一個計數。

+0

當你說「行結束」時,你是否在sprintf語句中建議\ n?我不遵循你所說的,你能告訴我嗎? –

+0

是的,這正是我的意思。否則,您可能會收到您發送的所有數據,如下所示:'「部門123部門456部門789」' – duskwuff

+0

這似乎不起作用。我仍然不得不壓低輸入以獲得下一行信息。 –

1

要添加黃昏的答案,您遇到的情況是需要使用基於流的協議的

因爲TCP不是面向消息的(不像UDP和其他更奇特的消息協議),所以發送和接收單個字節流。基本上,如果你認爲你的客戶是一本書的作者,而你的服務器是它的讀者,那麼在TCP世界中,所有標點符號都被刪除:)。

作爲程序員,您的工作是提供一種定義良好的方式,以便能夠編碼和/或嵌入一個消息/幀結束和下一個開始的位置。使用換行符是最簡單的方法,但是任何基於TCP的協議都可以使用長度或分隔符或其組合(請參閱HTTP)。

+0

原諒我在這裏,但沒有看到你說的如何幫助我?也許一個例子可能有幫助? –