목차
- C 언어 TCP 서버 소켓 예제 이전 포스팅
- malloc 동적 메모리 할당 관련 예제 이전 포스팅
- 파일의 크기를 읽고 버퍼 할당하기 예제
- 할당한 버퍼에 파일 데이터 저장 예제
- 저장된 파일 확인
C 언어 TCP 서버 소켓 예제 이전 포스팅
오늘 포스팅은 TCP 서버가 클라이언트로부터 파일 데이터를 받아 로컬에 저장하는 예제입니다. 따라서 본 포스팅 예제 수행을 하기 위해서는 서버 소켓을 생성하여 클라이언트 연결을 받고 메세지를 수신하는 방법에 대해 잘 알아야합니다. 이전 포스팅에서 다뤘던 C언어 서버 소켓 생성 예제 포스팅을 참고하여주세요.
아래는 해당 포스팅 링크입니다.
2023.08.12 - [Python/os] - [Python] socket TCP 서버 구성하기 예제(TCP, SO_REUSEADDR)
malloc 동적 메모리 할당 관련 예제 이전 포스팅
또한, 소켓 통신에 있어서 메세지를 주고받는 과정에 중요한 부분이 있습니다. 과연 클라이언트가 주는 파일 데이터가 얼만큼의 크기를 가지고 있는지가 중요합니다. 크기를 모르고 데이터를 수신할 수는 없기때문에 크기를 수신하고 그만큼의 버퍼를 할당해야합니다. 이 버퍼에 파일 데이터를 저장하기 위함이죠.
이전 포스팅에서 다뤘던 C언어에서 malloc 함수를 통해 동적 메모리 할당하는 방법에 대해 먼저 학습하고 아래 예제를 진행해주세요.
2023.08.09 - [C] - [C/C++] malloc 메모리 동적 할당 예제(포인터, free)
파일의 크기를 읽고 버퍼 할당하기 예제
아래는 서버가 클라이언트로부터 파일의 크기(4byte)를 읽고 malloc 함수로 메모리 동적할당을 하여 버퍼를 생성하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
// 서버 소켓 생성
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
printf("소켓 생성 오류\n");
exit(1);
}
// 서버 주소 설정
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(9999);
// 서버에 주소 할당
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
printf("주소 할당 오류\n");
close(server_fd);
exit(1);
}
// 클라이언트의 연결 대기
if (listen(server_fd, 5) == -1) {
printf("연결 대기 오류\n");
close(server_fd);
exit(1);
}
printf("서버가 대기 중...\n");
// 클라이언트와 연결
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len);
if (client_fd == -1) {
printf("연결 오류\n");
close(server_fd);
exit(1);
}
// 파일 크기 읽기
uint32_t file_size;
if (read(client_fd, &file_size, sizeof(file_size)) != sizeof(file_size)) {
printf("파일 크기 읽기 오류\n");
close(client_fd);
close(server_fd);
exit(1);
}
printf("수신된 파일 크기: %u 바이트\n", file_size);
// 버퍼 동적 할당
void *buffer = malloc(file_size);
if (buffer == NULL) {
printf("메모리 할당 오류\n");
close(client_fd);
close(server_fd);
exit(1);
}
printf("생성된 버퍼 주소 : %x\n\n", buffer);
// 연결 종료
close(client_fd);
close(server_fd);
// 할당된 메모리 해제
free(buffer);
return 0;
}
할당한 버퍼에 파일 데이터 저장 예제
아래는 이전에 할당한 버퍼에 뒤에 전송되는 클라이언트의 텍스트 파일 데이터를 저장하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
// 서버 소켓 생성
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
printf("소켓 생성 오류\n");
exit(1);
}
// 서버 주소 설정
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(9999);
// 서버에 주소 할당
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
printf("주소 할당 오류\n");
close(server_fd);
exit(1);
}
// 클라이언트의 연결 대기
if (listen(server_fd, 5) == -1) {
printf("연결 대기 오류\n");
close(server_fd);
exit(1);
}
printf("서버가 대기 중...\n");
// 클라이언트와 연결
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len);
if (client_fd == -1) {
printf("연결 오류\n");
close(server_fd);
exit(1);
}
// 파일 크기 읽기
uint32_t file_size;
if (read(client_fd, &file_size, sizeof(file_size)) != sizeof(file_size)) {
printf("파일 크기 읽기 오류\n");
close(client_fd);
close(server_fd);
exit(1);
}
printf("수신된 파일 크기: %u 바이트\n", file_size);
// 버퍼 동적 할당
void *buffer = malloc(file_size);
if (buffer == NULL) {
printf("메모리 할당 오류\n");
close(client_fd);
close(server_fd);
exit(1);
}
printf("생성된 버퍼 주소 : %x\n\n", buffer);
// 파일 데이터 수신
if (read(client_fd, buffer, file_size) != file_size) {
printf("파일 데이터 수신 오류\n");
free(buffer);
close(client_fd);
close(server_fd);
exit(1);
}
printf("파일 데이터 수신 완료\n");
FILE *file = fopen("/tmp/client_text.txt", "w");
if (file != NULL) {
fprintf(file, buffer);
fclose(file);
}
// 연결 종료
close(client_fd);
close(server_fd);
// 할당된 메모리 해제
free(buffer);
return 0;
}
저장된 파일 확인
아래와 같이 /tmp/client_text.txt 파일을 확인해보면 클라이언트가 보낸 텍스트 파일 내용이 정상적으로 저장되어있습니다.