2014-02-23 3 views
0

서버에서 클라이언트로 문자열을 보내고 서버가 해당 문자열을 실행하고 출력을 클라이언트로 다시 보내는 서버 및 클라이언트 프로그램을 만들려고합니다. 나는 리눅스에서 이것을하고 있으며, 왜 내 프로그램이 최소한의 일을하지 않는지 혼란 스럽다. 여기에 코드가 있습니다.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 행)로 수신합니다. 입력의 나머지 부분을 얻기 위해 고객 약속에 Enter를 계속 눌러야합니다. 나는이 시점에서 내가 더 이상 잘못하고있는 것을 알지 못한다는 것을 너무나 많이 시도했다.

먼저 서버 코드에서 문자열을 클라이언트로부터 수신 한 후에 문자열을 출력하는 printf("String=>%s<",str);이 있습니다. 그러나 서버가 String=>ls -l으로 출력을 인쇄하면 끝에있는 < 키가 어떻게 든 먹 힙니다. 그 일을해서는 안되니?

도움을 주시면 감사하겠습니다. 나는 초보자이며 이전에 프로세스 간 통신으로 파이프만을 사용했음을 명심하십시오. 이제 첫 번째 유닉스 소켓 프로그램을 만들고 싶습니다.

미리 감사드립니다.

+0

클라이언트 코드가 불균형 한'{} '로 인해 컴파일되지 않습니다. [sscce] (http://sscce.org) –

+0

게시 recv()/send() 매뉴얼 페이지를 자세히 읽어보십시오. 이 두 함수가 반드시 많은 바이트를 받거나 보내지는 않는다는 사실을 알게됩니다. 모든 데이터 나 터미네이터가 수신/전송 될 때까지 이러한 호출을 반복하여 반복하는 것은 좋은 생각입니다. 꼭 필요한 것은 아닙니다. – alk

+0

답장을 보내 주셔서 감사합니다. 내가 왜 그것을 지정하지 않은만큼 많은 바이트를 보낼 wouldnt는 이해가 안돼. 그러나 나는 그것을 위해 당신의 말을들을 것이다.).그래서 여러분은 길거나 짧은 문자열을 보내고 있다고 말하면서, 각 send()의 끝 부분에 "트랜잭션의 끝"(문자)을 추가 할 것이고, 상대방에게 그 문자를 찾도록 요청해야합니다 ? 내 코드에서 ENDTHETRANS() 함수를 호출하는 곳을 살펴 보자. 그것이 당신이 추천하고있는 해결책입니까? (하지만 recv를 사용할 때마다) –

답변

2

이와 같은 경우의 일반적인 문제는 SOCK_STREAM 소켓이 메시지 경계를 보존하지 않는다는 것을 인식하지 못하는 것입니다. 따라서 send 호출로 전송 된 데이터는 여러 개의 recv으로 분할되어 수신되거나 병합 될 수 있으며 복수 send은 하나의 recv으로 끝납니다. 가장 중요한 것은 커널 전송 버퍼가 가득 차면 send 호출이 부분 데이터 (요청 된 데이터 중 일부만 전송)를 작성하고 짧은 리턴 값을 리턴 할 수 있다는 것입니다. 이를 테스트하고 나머지 데이터를 다시 보내야합니다.

종종 나타나는 또 다른 문제는 라인 결말 문제입니다 (특히 Linux와 창 사이에서 이야기 할 때). 다른 쪽을 혼동시키는 클라이언트 또는 서버에 여분의 캐리지 리턴 문자 (\r)가있을 수 있습니다. 이러한 경우 인쇄 할 때 출력이 누락되거나 잘리는 경향이 있습니다.

편집

라인

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

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

동등하다 거기 오류라고 여부에 따라 0 또는 1로 T를 설정한다. 이 유형의 대부분의 오류와 마찬가지로 경고를 켜면 경고가 표시됩니다.

+0

내가 무엇을 제안합니까? 클라이언트 코드에서'recv()'를 while 루프 안에 넣으면 소켓에서 모든 것을 가져와야한다고 들었습니다. 그러나 그것은 그렇게하지 않습니다. 임은 ENDOFTRANSACTION이 읽혀지고 1로 끝나는 것을 추적하는'done' 변수를 사용합니다. –

+0

@ArmanIqbal : 질문에 대한 저의 의견을보십시오. 현재 send 루프에 receive 루프가 중첩되어있는 것처럼 보입니다. 그러나 들여 쓰기가 엉망이되고 어딘가에 누락 된'} '이 있기 때문에 명확하지 않습니다. –

+0

나는 그것을 고쳤다. 코드를 붙여 넣는 동안 나는 엉망이되었습니다. 그러나 이제 서버 코드가'recv()'를 호출 할 때 오류가 발생합니다. –