개발 공부/C,C++

C언어로 구현해본 간단한 웹서버

name2965 2022. 4. 7. 18:43
728x90

 

 

C언어를 공부하면서 웹서버도 한번 직접 만들어보고 싶다고 생각했었는데

 

찾아보니 C언어로도 웹서버를 만들수 있다고 해서 하나하나 공부해가면서 만들어봤습니다.

 

 

#include <sys/stat.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <time.h> 
#include <signal.h> 
#include "test.h" 
#include "test-network.h" 

#define PORT 80   
#define WEBROOT "./webroot" 

   
int logfd, sockfd;  
void handle_connection(int, struct sockaddr_in *, int); 
int get_file_size(int); 
void timestamp(int); 

void handle_shutdown(int signal) { 
   timestamp(logfd); 
   write(logfd, "Shutting down..\n", 16); 
   close(logfd); 
   close(sockfd); 
   exit(0); 
} 

int main(void) { 
   int new_sockfd, yes=1; 
   struct sockaddr_in host_addr, client_addr;  
   socklen_t sin_size; 

   logfd = open(LOGFILE, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); 
   if(logfd == -1) 
      fatal("opening log file"); 

   if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 
      fatal("in socket"); 

   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) 
      fatal("setting socket option SO_REUSEADDR"); 

   printf("Starting tiny web daemon..\n"); 
   if(daemon(1, 0) == -1) 
      fatal("forking to daemon process"); 
   
   signal(SIGTERM, handle_shutdown); 
   signal(SIGINT, handle_shutdown);  
   
   timestamp(logfd); 
   write(logfd, "Starting up..\n", 15); 
   host_addr.sin_family = AF_INET;     
   host_addr.sin_port = htons(PORT);    
   host_addr.sin_addr.s_addr = INADDR_ANY; 
   memset(&(host_addr.sin_zero), '\0', 8);

   if (bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1) 
      fatal("binding to socket"); 

   if (listen(sockfd, 20) == -1) 
      fatal("listening on socket"); 

   while(1) {   
      sin_size = sizeof(struct sockaddr_in); 
      new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); 
      if(new_sockfd == -1) 
         fatal("accepting connection"); 

      handle_connection(new_sockfd, &client_addr, logfd); 
   } 
   return 0; 
} 

void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr, int logfd) { 
   unsigned char *ptr, request[500], resource[500], log_buffer[500]; 
   int fd, length; 

   length = recv_line(sockfd, request); 
   
   sprintf(log_buffer, "From %s:%d \"%s\"\t", inet_ntoa(client_addr_ptr->sin_addr), ntohs(client_addr_ptr->sin_port), request); 

   ptr = strstr(request, " HTTP/");
   if(ptr == NULL) { 
      strcat(log_buffer, " NOT HTTP!\n"); 
   } else { 
      *ptr = 0; 
      ptr = NULL; 
      if(strncmp(request, "GET ", 4) == 0)  
         ptr = request+4; 
      if(strncmp(request, "HEAD ", 5) == 0)
         ptr = request+5; 
      if(ptr == NULL) {  
         strcat(log_buffer, " UNKNOWN REQUEST!\n"); 
      } else { 
         if (ptr[strlen(ptr) - 1] == '/')  
            strcat(ptr, "index.html");    
         strcpy(resource, WEBROOT);     
         strcat(resource, ptr);         
         fd = open(resource, O_RDONLY, 0); 
         if(fd == -1) { 
            strcat(log_buffer, " 404 Not Found\n"); 
            send_string(sockfd, "HTTP/1.0 404 NOT FOUND\r\n"); 
            send_string(sockfd, "Server: Tiny webserver\r\n\r\n"); 
            send_string(sockfd, "<html><head><title>404 Not Found</title></head>"); 
            send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n"); 
         } else {      
            strcat(log_buffer, " 200 OK\n"); 
            send_string(sockfd, "HTTP/1.0 200 OK\r\n"); 
            send_string(sockfd, "Server: Tiny webserver\r\n\r\n"); 
            if(ptr == request + 4) { 
               if( (length = get_file_size(fd)) == -1) 
                  fatal("getting resource file size"); 
               if( (ptr = (unsigned char *) malloc(length)) == NULL) 
                  fatal("allocating memory for reading resource"); 
               read(fd, ptr, length); 
               send(sockfd, ptr, length, 0); 
               free(ptr); 
            } 
            close(fd); 
         } 
      } 
   } 
   timestamp(logfd); 
   length = strlen(log_buffer); 
   write(logfd, log_buffer, length);

   shutdown(sockfd, SHUT_RDWR);
} 

int get_file_size(int fd) { 
   struct stat stat_struct; 

   if(fstat(fd, &stat_struct) == -1) 
      return -1; 
   return (int) stat_struct.st_size; 
} 

void timestamp(fd) { 
   time_t now; 
   struct tm *time_struct; 
   int length; 
   char time_buffer[40]; 

   time(&now); 
   time_struct = localtime((const time_t *)&now);
   length = strftime(time_buffer, 40, "%m/%d/%Y %H:%M:%S> ", time_struct); 
   write(fd, time_buffer, length);
}

 

 

직접 만들어보면서 공부해봐도 역시 웹은 너무 어려운것 같네요ㅠㅠ.

 

간단한 웹서버 하나 만들기도 이렇게 어렵다는걸 처음 알았습니다.

728x90

'개발 공부 > C,C++' 카테고리의 다른 글

C언어 학생성적 관리프로그램  (0) 2022.06.15