2014-02-23 27 views
0

我試圖創建一個服務器和客戶端程序,從客戶端向服務器發送一個字符串,服務器在其中執行該字符串並將輸出發送回客戶端。我在linux中這樣做,我很困惑爲什麼我的程序沒有工作。這是代碼。如何使用recv來接收長文本字符串

**Client** 
int main() 
{ 
    //Code to use unix socket here 

    if (connect(s, (struct sockaddr *)&remote, len) == -1) { 
     perror("connect"); 
     exit(1); 
    } 

    printf("Connected.\n"); 

    while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) { 
     if (send(s, str, strlen(str), 0) == -1) { 
      perror("send"); 
      exit(1); 
     } 
    } 
    done=0; 
    do { 
     if(t=recv(s, str, MAX, 0)<0) 
      perror("recv failed at client side!\n"); 
     str[t] = '\0'; 
     if(strcmp(str, "ENDOFTRANS")==0) 
     { 
      printf("\nRead ENDOFTRANS. Breaking loop.\n"); 
      done=1; 
     } 
     printf("Server > %s", str); 
    } while(!done); 
} 

,然後服務器代碼:

**Server** 

#define MAX 1000 
int main(void) 
{ 
//Unix socket code 

//This process is now a daemon. 
daemon(); 


//Listens for client connections, up to 5 clients can queue up at the same time. 
if (listen(s, 5) == -1) { 
    perror("listen"); 
    exit(1); 
} 

for(;;) { 
    int done, n, status; 

    printf("Waiting for a connection...\n"); 
    t = sizeof(remote); 

    if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) { 
      perror("accept"); 
      exit(1); 
    } 

      printf("Connected.\n"); 

    done = 0; 
    do { 
     switch(fork()) 
     { 
      case -1: //ERROR 
      perror("Could not fork.\n"); 
      break; 

      case 0: //CHILD 

      //Accept string from client. 
      //Edit: Why am I getting an error here? says: Invalid argument. 
      if(n = recv(newsock, str, MAX, 0)) { 
       perror("Recv error at server side.\n"); 
       exit(1); 
      } 
      str[n]='\0'; 
      if (n <= 0) { 
       if (n < 0) 
        perror("recv"); 
       done = 1; 
      } 
      printf("String=>%s<",str); 

      //Redirect socket to STDOUT & STDERR. 
      test = close(WRITE);  assert(test==0); 
      test = dup(newsock);  assert(test==WRITE); 
      test = close(ERROR);  assert(test==0); 
      test = dup(newsock);  assert(test==ERROR); 



      if (!done) 
      { 
       if (str==something) 
       { 
        //execute command 
       } 

       else { 
        //Fork and execvp the command 
       } 

       //Sends End of Transaction character. 
       ENDTHETRANS(); 
       exit(0); 
      } 
      break; 

      default: //PARENT 
       //Parent keeps accepting further clients. 
       wait(&status); 
       if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) { 
        perror("accept"); 
        exit(1); 
       } 

       printf("Connected.\n"); 
       done=1; 
       break; 

     } 
    } while (!done); 
} 
close(s); 
} 

進出口比較新的編程一般從我瞭解的客戶端代碼,例外的是好當它臨危文本從服務器返回它只以小比特(一次2行)接收文本。我必須不斷輸入客戶端Promt以獲取其餘的輸入。我已經嘗試了很多東西,到目前爲止,我甚至不知道自己做錯了什麼。

首先,在服務器代碼中,從客戶端收到字符串後,我有一個輸出字符串的printf("String=>%s<",str);。但是,當服務器打印輸出爲String=>ls -l時,<鍵最終會以某種方式被吃掉。它不應該這樣做嗎?

任何幫助非常讚賞。請記住,我是一名初學者,之前只使用管道作爲進程間通信。現在我想製作我的第一個unix套接字程序。

在此先感謝。

+0

您的客戶端代碼甚至因爲不平衡而無法編譯'{'''嘗試發佈[sscce](http://sscce.org) –

+0

仔細閱讀recv()/ send()並且瞭解到這兩個函數不一定會收到/發送儘可能多的字節,而只是很少。因此,圍繞此類調用進行計數,直到收到/發送所有數據或終結符都是一個好主意,而不是說必不可少。 – alk

+0

感謝您的答案@alk。我不明白爲什麼它不會像我指定的那樣發送儘可能多的字節。但我會接受你的話=)。所以你說的是我發送的長或短的字符串,我會在每個send()的末尾添加一個「結束事務」(字符),並且我應該要求另一端查找所述字符?看看我在調用ENDTHETRANS()函數的代碼中的一個地方。這是你所指的解決方案嗎? (但每次我使用recv?) –

回答

2

這種情況下的常見問題並未意識到SOCK_STREAM套接字不保留消息邊界。因此,通過send呼叫發送的數據可能會被拆分並接收到多個recv,或者它可能會合並,並且多個send最終以單個recv結尾。最重要的是,當內核發送緩衝區填滿時,send調用可能會寫入部分數據(僅發送一些請求的數據)並返回一個短暫的返回值。您需要對此進行測試並重新發送其餘數據。

經常出現的另一個問題是線結束的問題(特別是在linux和windows之間進行交談時)。客戶端或服務器中可能會有額外的回車字符(\r),這些字符會令對方感到困惑。這些往往會導致打印時顯然丟失或截斷輸出。

編輯

if(t=recv(s, str, MAX, 0)<0) 

相當於

if(t = (recv(s, str, MAX, 0)<0)) 

即,它取決於是否發生了錯誤或不設定T爲0或1。與大多數此類錯誤一樣,開啓警告會給您一些指示。

+0

你建議我做什麼?我被告知,在客戶端代碼中,如果我把'recv()'放在'while循環中',它應該從套接字中獲取所有內容。但它沒有這樣做。我使用'done'變量來跟蹤ENDOFTRANSACTION何時被讀取並且改變爲1. –

+0

@ArmanIqbal:請參閱我在問題中的評論。您目前似乎將接收循環嵌套在發送循環中,但尚不清楚,因爲縮進全部搞砸了,並且某處存在缺少'}的地方。 –

+0

我修正了這個問題。我在這裏複製粘貼代碼時搞砸了。然而,當服務器代碼調用'recv()'時,我現在得到一個錯誤。在'n = recv(newsock,str,MAX,0);' –