[socket programming] 간단한 webserver 구현

2020. 12. 11. 22:49CS/네트워크

webserver.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>

void error_handling(char *message);

int main(int argc, char *argv[]){
    int sock_serv;
    int sock_clnt;
    int port;

    struct sockaddr_in addr_serv;
    struct sockaddr_in addr_clnt;

    char buffer[1024];
    char path[1024];  //path 경로 설정
   char html[1024];

   if(argc!=2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    port = atoi(argv[1]);


    sock_serv = socket(PF_INET, SOCK_STREAM, 0);
   setsockopt(sock_serv, SOL_SOCKET, SO_REUSEADDR,  (struct sockaddr*)&addr_serv, sizeof(addr_serv));
    if(sock_serv == -1){
        error_handling("socket error");
    }//소켓 생성

    memset(&addr_serv, 0, sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
   addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_serv.sin_port = htons(port);


    if(bind(sock_serv, (struct sockaddr*)&addr_serv, sizeof(addr_serv)) == -1){
        error_handling("bind error!");
    }//바인드

    if(listen(sock_serv, 5) < -1){
        error_handling("listen error!");
    }
    while(1){
        int clnt_addr_size = sizeof(addr_clnt);
        sock_clnt = accept(sock_serv,(struct sockaddr*)&addr_clnt,&clnt_addr_size);

        if(sock_clnt == -1){
            error_handling("accept error!");
         break;
      }
        memset(path,0,1024);
        memset(buffer,0,1024);  //초기화
        memset(html,0,1024);

        int ret;
        ret = read(sock_clnt, buffer, 1024);

      if(buffer[0] == '\0'){
         strcpy(buffer,NULL);
      }

      int i = 0;
      int j = 0;
      int po = 0;
      int check = 0;

      for (i = 0; i < strlen(buffer); i++) {
            if (buffer[i] == 'G' && buffer[i + 1] == 'E' && buffer[i + 2] == 'T' && buffer[i + 3] == ' ') {
              for (j = 0; buffer[i + 4 + j] != ' '; j++) {
                   path[j] = buffer[i + 4 + j];
                }
              break;
            }else if (buffer[i] == 'P' && buffer[i + 1] == 'O' && buffer[i + 2] == 'S' && buffer[i + 3] == 'T' && buffer[i + 4] == ' ') {
            printf("star\n");
            po = 1;
              break;
          }
       }
       printf("request: %s \n",path);
      char *header =  "HTTP/1.1 200 OK\n""Content-type: text/html\n""\n";
      write(sock_clnt, header, strlen(header));

       if (strcmp(path, "/") == 0 || strcmp(path, "/index.html") == 0) {
         FILE* file; //파일
            if((file = fopen("index.html", "r")) == NULL) {
               printf("Error");
                exit(1);
            }
while (feof(file) == 0) {
              fread(buffer, sizeof(char), 1024, file);
              strcpy(html,buffer);
                memset(buffer, 0, 1024);
          }

         fclose(file);
         write(sock_clnt, html, strlen(html));
      }
      else if (strcmp(path, "/query.html") == 0) {
         FILE* file; //파일
            if((file = fopen("query.html", "r")) == NULL) {
               printf("Error");
                exit(1);
            }
         while (feof(file) == 0) {
              fread(buffer, sizeof(char), 1024, file);
              strcpy(html,buffer);
                memset(buffer, 0, 1024);
         }
         fclose(file);
         write(sock_clnt, html, strlen(html));
      }
      else if(po == 1){
         char * save;
         save = strstr(buffer,"name");
         char * t = "</h1>\n";
         char * t1 = "</body>";
         char * t2 = "</html>";
         strcpy(html,
         "<!DOCTYPE html>\n""<html>\n""<head>\n"
         "<title>POST Example</title>"
         "<meta name=\"viewport\" content=\"width=device-width, initial scale=1\">"
         "<link rel=\"icon\" href=\"data:,\">"
         "</head>\n"
           "<body>\n"
         "<h2>");
         strcat(html,save);
         strcat(html,t);
         strcat(html,t1);
         strcat(html,t2);
         write(sock_clnt, html, strlen(html));

      }
      else {
            strcpy(html,
           "<!DOCTYPE html>\n"
           "<html lang = \"ja\">\n"
           "<head>\n"
           "<meta charset = \"utf-8\">\n"
           "</head>\n"
           "<body>\n"
           "<h1>404- Not Found</h1>\n"
           "</body>"
           "</html>");
         write(sock_clnt, html, strlen(html));
       }
    }
   close(sock_clnt);
    close(sock_serv);
    return 0;
}

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n',stderr);
    exit(1);
}

index.html

<!DOCTYPE html>
<html>
<head>
    <title>My Web Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,">
</head>
<body>
    <h1>Welcome to My Web Page!</h1>
</body>
</html>

 

query.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>POST Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,">
</head>
<body>
<h2>Example of sending data using POST</h2>
<form action="/sample" method="post">
    Name:
    <input type="text" name="name"/><br/>
    Student number:
    <input type="text" name="snumber"/><p/>
    <input type="submit" value="submit"/>
</form>
</body>
</html>

 

아쉬운 : 404 page 내가 입력해서 출력하는 것이 아니라 브라우저 자체의 페이지로 요청받았으면 좋았을