Created
July 27, 2019 09:20
-
-
Save surinoel/db70ca459114a5370d31e8d114b84eef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <pthread.h> | |
| #include <arpa/inet.h> | |
| #include <sys/socket.h> | |
| #define BUF_SIZE 1024 | |
| #define SMALL_BUF 100 | |
| void *request_handler(void *arg); | |
| void send_data(FILE *fp, char *ct, char *file_name); | |
| char *content_type(char *file); | |
| void send_error(FILE *fp); | |
| int main(int argc, char **argv) | |
| { | |
| int serv_sock, clnt_sock; | |
| struct sockaddr_in serv_addr, clnt_addr; | |
| socklen_t clnt_addr_size; | |
| char buf[BUF_SIZE]; | |
| pthread_t t_id; | |
| if(argc != 2) { | |
| printf("Usage : %s <port>\n", argv[0]); | |
| return -1; | |
| } | |
| serv_sock = socket(AF_INET, SOCK_STREAM, 0); | |
| if(serv_sock < 0) { | |
| perror("socket"); | |
| return -1; | |
| } | |
| memset(&serv_addr, 0, sizeof(serv_addr)); | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
| serv_addr.sin_port = htons(atoi(argv[1])); | |
| if(bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("bind"); | |
| return -1; | |
| } | |
| if(listen(serv_sock, 5) < 0) { | |
| perror("listen"); | |
| return -1; | |
| } | |
| while(1) { | |
| clnt_addr_size = sizeof(clnt_addr); | |
| clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size); | |
| if(clnt_sock < 0) { | |
| perror("accept"); | |
| return -1; | |
| } | |
| printf("Connection Request : %s:%d\n", | |
| inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port)); | |
| pthread_create(&t_id, NULL, request_handler, (void *)&clnt_sock); | |
| pthread_detach(t_id); | |
| } | |
| close(serv_sock); | |
| return 0; | |
| } | |
| void *request_handler(void *arg) | |
| { | |
| int clnt_sock = *((int *)arg); | |
| char req_line[SMALL_BUF]; | |
| FILE *clnt_read; | |
| FILE *clnt_write; | |
| char method[10]; | |
| char ct[15]; | |
| char file_name[30]; | |
| // 파일 포인터로 제어하기 위해 fd를 fp로 전환 | |
| clnt_read = fdopen(clnt_sock, "r"); | |
| clnt_write = fdopen(dup(clnt_sock), "w"); | |
| fgets(req_line, SMALL_BUF, clnt_read); | |
| // 먼저 HTTP 프로토콜인지 확인하기 위해 strstr 함수로 substring을 찾음 | |
| if(strstr(req_line, "HTTP/") == NULL) { | |
| send_error(clnt_write); | |
| fclose(clnt_read); | |
| fclose(clnt_write); | |
| return NULL; | |
| } | |
| /* | |
| 요청 라인은 예를 들어 | |
| GET /index.html HTTP/1.1로 구성되어 있다 | |
| */ | |
| // strtok에 ' ', '/'을 delimeter로 해서 추출한다 | |
| strcpy(method, strtok(req_line, " /")); // GET | |
| strcpy(file_name, strtok(NULL, " /")); // index.html | |
| strcpy(ct, content_type(file_name)); // text.html | |
| if(strcmp(method, "GET") != 0) { | |
| send_error(clnt_write); | |
| fclose(clnt_read); | |
| fclose(clnt_write); | |
| return NULL; | |
| } | |
| if(strcmp(file_name, "index.html") != 0) { | |
| send_error(clnt_write); | |
| fclose(clnt_read); | |
| fclose(clnt_write); | |
| return NULL; | |
| } | |
| fclose(clnt_read); | |
| send_data(clnt_write, ct, file_name); | |
| return NULL; | |
| } | |
| void send_data(FILE *fp, char *ct, char *file_name) | |
| { | |
| /* | |
| 응답 헤더 | |
| */ | |
| char protocol[] = "HTTP/1.0 200 OK\r\n"; | |
| char server[] = "Server:Linux Web Server \r\n"; | |
| char cnt_len[] = "Content-length:2048\r\n"; | |
| char cnt_type[SMALL_BUF]; | |
| char buf[BUF_SIZE]; | |
| FILE *send_file; | |
| sprintf(cnt_type, "Content-type:%s\r\n\r\n", ct); // 마지막에 개행 2번을 해줘야 한다 | |
| send_file = fopen(file_name, "r"); | |
| if(send_file == NULL) { | |
| send_error(fp); | |
| return; | |
| } | |
| /* 헤더 정보 전송 */ | |
| fputs(protocol, fp); | |
| fputs(server, fp); | |
| fputs(cnt_len, fp); | |
| fputs(cnt_type, fp); | |
| // html 정보 전달 | |
| while(fgets(buf, BUF_SIZE, send_file) != NULL) { | |
| fputs(buf, fp); | |
| fflush(fp); | |
| } | |
| fflush(fp); | |
| fclose(fp); | |
| return; | |
| } | |
| char *content_type(char *file) | |
| { | |
| char extension[SMALL_BUF]; | |
| char file_name[SMALL_BUF]; | |
| strcpy(file_name, file); | |
| strtok(file_name, "."); | |
| strcpy(extension, strtok(NULL, ".")); | |
| if(!strcmp(extension, "html") || !strcmp(extension, "htm")) | |
| return "text/html"; | |
| else | |
| return "text/plain"; | |
| } | |
| void send_error(FILE *fp) | |
| { | |
| char protocol[] = "HTTP/1.0 400 Bad Request\r\n"; | |
| char server[] = "Server:Linux Web Server \r\n"; | |
| char cnt_len[] = "Content-length:2048\r\n"; | |
| char cnt_type[] = "Content-type:text/html\r\n\r\n"; | |
| char content[] = "<html><head><title>NETWORK</title></head>" | |
| "<body><font size=+5><br>Error" | |
| "</font></body></html>"; | |
| fputs(protocol, fp); | |
| fputs(server, fp); | |
| fputs(cnt_len, fp); | |
| fputs(cnt_type, fp); | |
| fputs(content, fp); | |
| fflush(fp); | |
| return; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment