C언어 Newwork Study 3

2025. 7. 11. 23:11·C/Study

 

 

 

 

 

 

 

 

 

 

 

 

🌟 4-3 에코 클라이언트의 문제점

더보기
// echo_server.c

while((str_len = read(clnt_sock, message, BUF_SIZE)) != 0)
    write(clnt_sock, message, str_len);

// 서버는 클라이언트로부터 데이터를 여러 번에 걸쳐 수신할 수 있다고 생각하고 read()를 반복 호출함.
// 수신한 만큼만 write()로 다시 전송함.
// ehco_client

write(sock, message, strlen(message));
str_len = read(sock, message, BUF_SIZE-1);

// 클라이언트는 문자열을 한 번에 전송함
// read()도 한 번만 호출해서 모든 데이터가 한 번에 수신되기를 기대함

 

 

해결책 1: read()를 반복해서 호출하여 원하는 길이만큼 수신

  • 방법: 클라이언트가 write()를 통해 보낸 데이터의 길이만큼 수신이 완료될 때까지 read()를 반복 호출해야 함.
  • 이유: read()는 최대 BUF_SIZE-1 바이트까지만 읽을 수 있고, 실제로는 그보다 더 적은 바이트가 수신될 수 있음. 따라서 read()를 한 번만 호출하면 불완전한 데이터 수신이 발생할 수 있음
// 서버에 메시지 전송 (write 반환값은 전송한 바이트 수)
int str_len = write(sock, message, strlen(message));

// 지금까지 수신한 총 바이트 수를 저장할 변수
int recv_len = 0, recv_cnt;

// 서버로부터 str_len 바이트를 모두 수신할 때까지 반복
while (recv_len < str_len) {
    // 남은 공간에 데이터 수신 (최대 BUF_SIZE - 1 - recv_len 바이트)
    recv_cnt = read(sock, &message[recv_len], BUF_SIZE - 1 - recv_len);
    
    // read 오류 처리
    if (recv_cnt == -1)
        error_handling("read() error!");
    
    // 누적 수신 바이트 수 갱신
    recv_len += recv_cnt;
}

// 문자열 끝에 널 문자 추가 (C 문자열로 만들기 위함)
message[recv_len] = 0;

// 서버로부터 받은 메시지 출력
printf("Message from server: %s", message);

 

 

해결책 2: 응답 종료 조건을 지정 (ex. 종료 구분자 사용)

  • 방법: 서버가 응답 데이터의 끝에 구분자 문자(예: \n, \0, "END" 등)를 추가로 전송하고 클라이언트는 그 구분자를 만날 때까지 read()를 반복
  • 이유: 메시지의 길이를 사전에 알 수 없는 경우, 수신이 완료되었는지를 판단하기 위한 종료 기준이 필요함 종료 구분자를 사용하면 정확한 길이를 몰라도 수신을 마칠 수 있음
char ch;        // 한 글자씩 수신할 문자 변수
int idx = 0;    // message 배열의 인덱스

// 무한 루프: 종료 구분자('\n')가 수신될 때까지 계속 수신
while (1) {
    // 1바이트 읽어서 ch에 저장
    if (read(sock, &ch, 1) <= 0)
        error_handling("read() error!");

    // 읽은 문자를 message 배열에 저장
    message[idx++] = ch;

    // 개행 문자('\n')가 수신되면 루프 종료
    if (ch == '\n')  
        break;
}

// 문자열 끝에 널 문자 추가 (C 문자열로 만들기 위함)
message[idx] = 0;

// 서버로부터 받은 메시지 출력
printf("Message from server: %s", message);

 

 

  • TCP는 데이터를 바이트 스트림으로 전달하기 때문에 한 번에 보낸 메시지가 한 번에 도착하는 보장이 없음. 이로 인해 클라이언트에서 read()를 한 번만 출력하면 데이터가 일부 수신될 가능성↑

 

  • 이를 해결할 방법 2가지. 첫째, write()로 보낸 데이터만큼 read()를 반복 호출하는 방식. 이 방식은 전송한 데이터 크기를 클라이언트가 알고 있을 경우 매우 적합. read()를 반복 호출하여 누적 수신 바이트 수가 전송한 바이트 수와 일치할 때까지 수신을 계속함. 이로 인해 위에 언급한 문제를 방지할 수 있음. 둘째, 서버가 메시지 끝에 구분자(예: \n, "END")를 붙이고, 클라이언트가 이를 만날 때까지 read()를 반복하는 방식! 이 방식은 구분자가 도착하면 수신이 완료됐음을 판단할 수 있기에 메시지 처리에 효과적이다. 다만 서버와 클라이언트가 구분자에 대한 사전 약속을 해야 함.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'C > Study' 카테고리의 다른 글

C언어 Newwork Study 5  (1) 2025.07.11
C언어 Newwork Study 4  (1) 2025.07.11
C언어 Newwork Study 2  (1) 2025.07.11
C언어 Newwork Study 1  (0) 2025.06.30
'C/Study' 카테고리의 다른 글
  • C언어 Newwork Study 5
  • C언어 Newwork Study 4
  • C언어 Newwork Study 2
  • C언어 Newwork Study 1
eull
eull
eull 님의 블로그 입니다.
  • eull
    eull 님의 블로그
    eull
  • 전체
    오늘
    어제
    • 개발 환경 (34)
      • Qt (2)
        • API (0)
        • Project (2)
      • MYSQL_Workbench (1)
        • setting (1)
      • Linux_Ubuntu (2)
        • Task (1)
        • Setting (1)
      • C (19)
        • Concept (4)
        • Task (8)
        • Project (1)
        • Study (5)
        • Setting (1)
      • C++ (1)
        • Study (0)
        • Concept (1)
      • Python (6)
        • Task (4)
        • Project (2)
      • 일상 (1)
      • Setting (1)
      • 홍보 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    #광주인력개발원#대한상공회의소#상공회의소#인력개발원#청년#일경험#ESG#청년일경험&#160;#오텍캐리어#수당100만원#광주#구직단념#그린#Green#취준생#이력서#취업준비#취업맛집&#160;#취업우수기관#국비교육#대학생#ESG지원형
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
eull
C언어 Newwork Study 3
상단으로

티스토리툴바