2012-06-21 3 views
3

c에서 클라이언트의 서버로 줄 단위로 파일을 보내려면 c로 프로그램을 작성했습니다. 파일이 완전히 전송 된 후 파일이 끝났고 다음 파일이 다음에 전송되고 있음을 확인하기 위해 서버에서 문자열 비교를 위해 txt 파일에 endoffile 줄을 제공했습니다. 다음 파일은 서버의 다른 파일에 기록되어야합니다. 하지만 문제는 strcmp가 코드에서 endoffile을 결코 감지하지 못하기 때문에 클라이언트의 파일에서 동일한 문자열로 endoffile이 수신되었다는 것입니다. amd는 클라이언트의 다음 파일을 서버의 동일한 파일에 계속 작성합니다.TCP를 통한 전송에서 문자열 비교 오류가 발생했습니다.

char enof[]="endoffile"; 
... 
do 
{ 
    rewind(appcrt); 
    bytes_recieved = recv(pass_arg.connected, recv_data_c, strlen(recv_data_c), 0); 
    recv_data_c[bytes_recieved-1] = '\0'; 
    fputs(recv_data_c, appcrt); 
    if(strcmp(enof,recv_data_c) == 0){break;} 
}while(check<count); 

텍스트 파일 :

Necessary data 
that is 
being transmitted 
to be written to the file 
endoffile 

txt 파일에서 읽고 서버로 전송하기 위해 사용되는 코드 : 내가 지금 상태에서 확인해야하는 내용을 변경

while (fgets(line, sizeof(line), crt) != NULL) 
{ 
    send(sock, line, sizeof(line), 0); 
} 

문제가 해결되고 코드가 do....while(); 루프에서 종료됩니다. 미리 감사드립니다. 운영 플랫폼 : 리눅스

EDIT1는 다음과 같이 do....while()을 편집 :

do 
    { 
     rewind(appcrt); 
     bytes_recieved = recv(pass_arg.connected, recv_data_c, 100, 0); 
     recv_data_c[bytes_recieved] = '\0'; 
     fputs(recv_data_c, appcrt); 
     printf("%s-%s",enof,recv_data_c); 
     //if(strcmp(enof,recv_data_c) == 0){break;} 
    }while(check<count); 

터미널에서 다음과 같은 결과를 얻었다 : 아직도

endoffile-file1line1 
endoffile-file1line2 
endoffile-file1line3 
endoffile-file1line4 
endoffile-file1line5 
endoffile-file1line6 
endoffile-endoffile 
endoffile-file2line1 
endoffile-file2line2 
endoffile-file2line3 
endoffile-file2line4 
endoffile-file2line5 
endoffile-file2line6 
. 
. 
. 

희망도.

+1

'strlen (recv_data_c)'는 매우 의심 스럽습니다. 문자열이 처음에는 비어 있으면 아무것도 수신하지 않습니다. 그 위에, 반환 값이 0 또는 음수이고 인덱스 -1에서 배열에 액세스하거나 그보다 더 나쁜 경우는 어떻게됩니까? 나는 당신이 그것들을 고치고 print statement를 추가하여 처음에 그것이 무엇을 받는지보기를 권한다. –

+0

'recv_data_c'가 문자의 배열이라고 가정하면'recv' 호출에서'strlen (recv_data_c)'대신'sizeof (recv_data_c) -1'을 전달해보십시오. –

+0

@VladLazarenko : 그뿐만 아니라, NUL 바이트가 잘못된 시간에 전송되면 해킹에 큰 위험이 될 수 있습니다. – Linuxios

답변

1
while (fgets(line, sizeof(line), crt) != NULL) 
{ 
    send(sock, line, sizeof(line), 0); 
} 

fgets()은 행이 비어 있으면 1 바이트 만 읽을 수 있습니다. 따라서 귀하의 send() 호출은 모든 호출 (이전 회선 내용 또는 임의의 메모리 free() d) 이전에 응용 프로그램에 의해 많은 양의 초기화되지 않은 데이터를 전송합니다.

따라서, 귀하의 수신 프로그램은 비교할 필요가있다 :

endoffiletten to the file 

마침내 최종 문자열을 참조 할 수 있습니다. line 버퍼가 ASCII NUL 문자로 시작되었다고 가정하십시오.

+0

리눅스와 같은 현대의 커널이 당신을 다른 프로세스의 메모리로 보일 것이라고는 생각하지 않습니다. 너는 단념 할거야. – Linuxios

+0

@Linuxios : 하! 'malloc()'은 제 시스템에서 제로 된 페이지를 리턴합니다. 그림을 이동. (또는 적어도 간단한 테스트 프로그램을 6 회 반복 실행하면 0을 계속 표시합니다.) – sarnold

+0

좋은 지적 이었지만 모든 OS의 * Linux *를 상상할 수는 없습니다. -zeroed 또는 non-random 페이지. – Linuxios

2

클라이언트가 소켓에 한 번에 한 행을 쓰더라도 소켓을 통해 전송 된 데이터가 그대로 사용되므로 서버가이를 소비하지 않습니다 바이트의 스트림 서버는 다음 줄 문자를 읽고 비교해야합니다. 간단한 알고리즘은 한 번에 바이트를 읽고는 개행 문자인지 확인하고 경우 개행 문자를 읽을 때까지 문자열로를 추가하지 않을 : 그 외에도

/* Read next line. */ 
memset(line, 0, sizeof(line)); 
size_t line_len = 0; 
while (line_len < sizeof(line) - 1 && 
     1 == recv(pass_arg.connected, &line[line_len], 1, 0)) 
{ 
    if ('\n' == line[line_len]) break; 
    line_len++; 
} 

, 몇 가지 문제가있다 코드와 함께 :

  • 당신은이 sizeof(line)보다 적을 수 있습니다으로 파일에서 읽은 무엇을 보내야합니다.

    send(sock, line, sizeof(line), 0); 
    

    에 :

    send(sock, line, strlen(line), 0); 
    

    를하고 성공하는 경우도 결정 send()의 반환 값을 확인 변경합니다.

  • 이 단지 이전에 읽은 (또는 빈 문자열 아무것도 초기화 된 경우 읽히는) 무슨 최대 읽기 것처럼 다음은 올바르지 않습니다 반환을 확인, 다시

    bytes_recieved = recv(pass_arg.connected, 
              recv_data_c, strlen(recv_data_c), 0); 
    

    하고, 특히 반환 값이 배열을 인덱싱하는 데 사용되는 값입니다. recv()이 실패하면 -1을 반환하므로 배열에서 범위를 벗어난 액세스로 인해 정의되지 않은 동작이 발생합니다.