이 블로그 게시물에서는 HTML 파일을 제공할 수 있는 C로 간단한 TCP 서버를 만드는 방법을 살펴보겠습니다. 우리는 코드를 분석하고, 그것이 어떻게 작동하는지 설명하고, 이 프로젝트를 향상시키기 위한 향후 계획에 대해 논의할 것입니다. 이는 프로세스를 지나치게 복잡하게 하지 않고 C에서 "단순히 작업을 수행"할 수 있는 방법을 보여주는 훌륭한 예입니다!
이 프로젝트의 목표는 클라이언트 연결을 수신하고 요청 시 HTML 파일을 제공하는 기본 TCP 서버를 구현하는 것입니다. 서버는 클라이언트 요청을 처리하고 지정된 HTML 파일을 읽은 다음 콘텐츠를 HTTP 응답으로 클라이언트에 다시 보냅니다.
코드를 정리하기 위해 프로젝트를 다음과 같이 구성하겠습니다.
tcp_server_c/ ├── CMakeLists.txt # Build configuration ├── include/ │ ├── server.h # Main server header file │ ├── html_serve.h # Header for serve_html function │ ├── request_handler.h # Header for handle_client function │ └── socket_utils.h # Header for socket utility functions ├── src/ │ ├── server.c # Main server program │ ├── html_serve.c # serve_html function │ ├── request_handler.c # handle_client function │ └── socket_utils.c # Utility functions for socket operations └── README.md # Project documentation
먼저 소켓 초기화를 처리하는 유틸리티 파일을 만들어 보겠습니다. 이렇게 하면 메인 서버 코드가 깔끔하고 집중된 상태로 유지됩니다.
include/socket_utils.h
#ifndef SOCKET_UTILS_H #define SOCKET_UTILS_H #includeint initialize_server(struct sockaddr_in* address); #endif
src/socket_utils.c
#include "socket_utils.h" #include#include #include #include #define PORT 8080 int initialize_server(struct sockaddr_in* address) { int server_fd; int opt = 1; if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket failed!"); return -1; } if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) { perror("setsockopt failed"); close(server_fd); return -1; } address->sin_family = AF_INET; address->sin_addr.s_addr = INADDR_ANY; address->sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr*)address, sizeof(*address)) 2. HTML 제공 기능
다음으로 HTML 파일을 제공하는 함수를 만듭니다. 이 함수는 HTML 파일의 내용을 읽고 이를 호출자에게 반환합니다.
include/html_server.h
#ifndef HTML_SERVER_H #define HTML_SERVER_H char* serve_html(const char* filename); #endifsrc/html_server.c
#include "html_server.h" #include#include #include char* serve_html(const char* filename) { FILE* file = fopen(filename, "r"); if (!file) { perror("Error opening file"); return NULL; } fseek(file, 0, SEEK_END); long length = ftell(file); fseek(file, 0, SEEK_SET); char* buffer = malloc(length 1); if (!buffer) { perror("Error allocating memory"); fclose(file); return NULL; } fread(buffer, 1, length, file); buffer[length] = '\0'; // Null-terminate the buffer fclose(file); return buffer; } 3. 클라이언트 요청 처리
이제 들어오는 클라이언트 요청을 처리하는 로직을 구현해 보겠습니다.
include/request_handler.h
#ifndef REQUEST_HANDLER_H #define REQUEST_HANDLER_H #includevoid handle_client(int new_socket); #endif src/request_handler.c
#include "request_handler.h" #include "html_server.h" #include#include #include #define BUFFER_SIZE 1024 void handle_client(int new_socket) { char buffer[BUFFER_SIZE] = { 0 }; read(new_socket, buffer, BUFFER_SIZE); // Serve the HTML file char* html_content = serve_html("../html/index.html"); if (html_content) { write(new_socket, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n", 48); write(new_socket, html_content, strlen(html_content)); } else { const char* not_found_response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n 404 Not Found
"; write(new_socket, not_found_response, strlen(not_found_response)); } free(html_content); close(new_socket); // Close the connection with the current client }4. 메인 서버 로직
마지막으로 모든 것을 메인 파일에 모아보겠습니다.
src/main.c
#include#include #include #include #include #include "socket_utils.h" #include "request_handler.h" int main() { int server_fd, new_socket; struct sockaddr_in address; int addrlen = sizeof(address); server_fd = initialize_server(&address); if (server_fd == -1) { return EXIT_FAILURE; } printf("Server listening on port: 8080\n"); while (1) { if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) 향후 계획
앞으로 우리는 다음과 같은 몇 가지 개선 사항과 기능을 구현할 계획입니다.
- 멀티스레딩 지원: 여러 클라이언트 연결을 동시에 처리하기 위해 서버 효율성을 향상시키는 스레딩 기능을 도입합니다.
- 동적 콘텐츠 제공: 경량 템플릿 엔진과 통합하여 동적 콘텐츠를 제공하는 기능을 구현합니다.
- 로깅: 요청, 오류 및 서버 성능을 추적하는 로깅 메커니즘을 추가합니다.
- 보안 기능: 보안을 강화하기 위해 HTTPS 지원 및 입력 유효성 검사를 추가해 보세요.
- 향상된 오류 처리: 파일을 찾을 수 없음, 서버 과부하 등과 같은 다양한 시나리오에 대해 더 나은 오류 처리를 구현합니다.
결론
이 간단한 TCP 서버 프로젝트는 C로 웹 서버를 만드는 방법에 대한 기본 예제 역할을 하며 언어의 강력함과 단순성을 보여줍니다. 이러한 기반을 바탕으로 보다 정교한 기능을 개발하고 성능을 향상시켜 웹 콘텐츠 제공을 위한 강력한 솔루션으로 만들 수 있습니다.
GitHub: GitHub Repository Link에서 전체 소스 코드를 찾고 프로젝트에 기여할 수 있습니다.
부담없이 피드백을 제공하고, 질문하고, 향후 개선을 위한 아이디어를 제공해주세요!
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3