diff --git "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article1.html" b/assignment/network/http/simple_webserver/seoneui/article1.html similarity index 100% rename from "assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article1.html" rename to assignment/network/http/simple_webserver/seoneui/article1.html diff --git "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article2.html" b/assignment/network/http/simple_webserver/seoneui/article2.html similarity index 100% rename from "assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article2.html" rename to assignment/network/http/simple_webserver/seoneui/article2.html diff --git "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article3.html" b/assignment/network/http/simple_webserver/seoneui/article3.html similarity index 100% rename from "assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/article3.html" rename to assignment/network/http/simple_webserver/seoneui/article3.html diff --git a/assignment/network/http/simple_webserver/seoneui/client b/assignment/network/http/simple_webserver/seoneui/client new file mode 100755 index 0000000..85be456 Binary files /dev/null and b/assignment/network/http/simple_webserver/seoneui/client differ diff --git a/assignment/network/http/simple_webserver/seoneui/client.cpp b/assignment/network/http/simple_webserver/seoneui/client.cpp new file mode 100644 index 0000000..f1acdd3 --- /dev/null +++ b/assignment/network/http/simple_webserver/seoneui/client.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +const int BUFFER_SIZE = 1024; +int PORT = 8080; + +int main() +{ + int clientSockcet; + struct sockaddr_in server; + char message[BUFFER_SIZE], server_reply[BUFFER_SIZE]; + char buffer[1024]; + + clientSockcet = socket(AF_INET, SOCK_STREAM, 0); + if (clientSockcet < 0) + { + cout << "소켓 생성 실패" << endl; + } + + cout << "소켓 생성 성공" << endl; + + // 서버 주소 설정 + struct sockaddr_in serverAddress; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(PORT); + + if (inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr) <= 0) + { + printf("\nInvalid address/ Address not supported \n"); + return -1; + } + + if (connect(clientSockcet, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) + { + cout << "연결 실패" << endl; + exit(1); + } + while (1) + { + strcpy(message, "GET /index.html HTTP/1.1\r\n\r\n"); + + if (send(clientSockcet, message, strlen(message), 0) < 0) + { + cout << "전송 실패" << endl; + exit(1); + } + + read(clientSockcet, buffer, 1024); + cout << buffer << endl; + } + return 0; +} \ No newline at end of file diff --git "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/index.html" b/assignment/network/http/simple_webserver/seoneui/index.html similarity index 100% rename from "assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/index.html" rename to assignment/network/http/simple_webserver/seoneui/index.html diff --git a/assignment/network/http/simple_webserver/seoneui/server b/assignment/network/http/simple_webserver/seoneui/server new file mode 100755 index 0000000..2b68be8 Binary files /dev/null and b/assignment/network/http/simple_webserver/seoneui/server differ diff --git a/assignment/network/http/simple_webserver/seoneui/server.cpp b/assignment/network/http/simple_webserver/seoneui/server.cpp new file mode 100644 index 0000000..a69f989 --- /dev/null +++ b/assignment/network/http/simple_webserver/seoneui/server.cpp @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +const int PORT = 8080; +const int BUFFER_SIZE = 1024; +const int MAX_EVENT = 1000; + +#define HEADER_FMT "HTTP/1.1 %d %s\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n" + +using namespace std; + +// http 해더 형식 지정 함수 +void fill_header(char *header, int status, long len, char *type) +{ + char status_text[40]; // http응답 상태 코드에 해당하는 텍스트 저장 + switch (status) + { + case 200: + strcpy(status_text, "OK"); // status_text에 적절한 텍스트 복사 + break; + case 404: + strcpy(status_text, "NOT FOUND"); + break; + case 500: + default: + strcpy(status_text, "Internet Server Error"); + break; + } + sprintf(header, HEADER_FMT, status, status_text, len, type); // header문자열에 http응답 헤더를 형식화해서 삽입 +} + +// 404 에러 처리 +void handle_404(int acceptSocket, char *type) +{ + char header[BUFFER_SIZE]; + char body[BUFFER_SIZE]; + + sprintf(body, "

404 Not Found

"); + fill_header(header, 404, strlen(body), type); + write(acceptSocket, header, strlen(header)); + write(acceptSocket, body, strlen(body)); +} + +// 500 에러 처리 +void handle_500(int acceptSocket, char *type) +{ + char header[BUFFER_SIZE]; + char body[BUFFER_SIZE]; + + sprintf(body, "

500 Internal Server Error

"); + fill_header(header, 500, strlen(body), type); + write(acceptSocket, header, strlen(header)); + write(acceptSocket, body, strlen(body)); +} + +// uri에서 MIME 타입을 찾는 함수 +void find_mime(char *ct_type, char *uri) +{ + char *ext = strrchr(uri, '.'); + if (!strcmp(ext, ".html")) + { + strcpy(ct_type, "text/html"); + } +} + +// 클라이언트로부터 받은 http 요청을 처리하고 응답을 보냄 +void httpHandler(int acceptSocket) +{ + int waitTime = rand() % 3000000 + 1000000; // 1,000,000에서 3,000,000 마이크로초(1~3초) 사이의 랜덤 값 + usleep(waitTime); // 랜덤 시간만큼 대기 + + char buf[BUFFER_SIZE]; + char response[BUFFER_SIZE * 2]; // 충분한 크기를 가지도록 조정 + char safe_uri[BUFFER_SIZE]; + struct stat st; + + // 요청 읽기 + read(acceptSocket, buf, BUFFER_SIZE - 1); + + cout << buf << endl; + + // HTTP 메서드와 URI 파싱 + char *method = strtok(buf, " "); + char *uri = strtok(NULL, " "); + + // 기본 URI 설정 + strcpy(safe_uri, uri); + if (!strcmp(safe_uri, "/")) + { + strcpy(safe_uri, "/index.html"); + } + + char *local_uri = safe_uri + 1; // 경로 앞의 '/' 제거 + + // MIME 타입 찾기 및 헤더 채우기 + char ct_type[40] = "text/plain"; // 기본 MIME 타입 + find_mime(ct_type, local_uri); // MIME 타입 찾기 + + // GET 메서드만 처리 + if (strcmp(method, "GET") != 0) + { + handle_500(acceptSocket, ct_type); + return; + } + + if (stat(local_uri, &st) < 0) + { + handle_404(acceptSocket, ct_type); + return; + } + + // 파일 열기 + int fd = open(local_uri, O_RDONLY); + if (fd < 0) + { + handle_500(acceptSocket, ct_type); + return; + } + + // 응답 헤더 생성 + char header[BUFFER_SIZE]; + fill_header(header, 200, st.st_size, ct_type); + + // 헤더와 파일 내용을 response 버퍼에 복사 + strcpy(response, header); + int header_len = strlen(header); + int cnt = read(fd, response + header_len, BUFFER_SIZE - header_len - 1); + if (cnt < 0) + { + // 파일 읽기 실패 + handle_500(acceptSocket, ct_type); + close(fd); + return; + } + + // 클라이언트에 응답 전송 + write(acceptSocket, response, header_len + cnt); + + close(fd); +} + +int main() +{ + srand(time(NULL)); + + struct sockaddr_in remote_sin; + int serverSocket = socket(AF_INET, SOCK_STREAM, 0); // 소켓 생성 + int kq; + + // 소켓에 에러가 발생한 경우 처리 + if (serverSocket < 0) + { + cout << "소켓 생성 실패" << endl; + exit(1); + } + + // 서버 주소 설정 + struct sockaddr_in serverAddress; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(PORT); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + // 소켓에 ip주소와 포트 번호 바인딩 + if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) + { // 만약 -1일 경우(실패) + cout << "바인딩 실패" << endl; + close(serverSocket); + exit(1); + } + + cout << "바인드 성공" << endl; + + // 소켓을 listen 상태로 전환함 + if (listen(serverSocket, 100) < 0) + { //-1일 경우(실패) + cout << "소켓 리스닝 실패" << endl; + exit(1); + } + + cout << "소켓 리스닝 성공" << endl; + + kq = kqueue(); + struct kevent changeEvent; + struct kevent eventList[MAX_EVENT]; // 이벤트 목록 + + // 서버 소켓에 대한 이벤트 등록 + EV_SET(&changeEvent, serverSocket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); + if (kevent(kq, &changeEvent, 1, NULL, 0, NULL) == -1) { + cout << "kevent 등록 실패" << endl; + exit(1); + } + + while (true) { + int newEvents = kevent(kq, NULL, 0, eventList, MAX_EVENT, NULL); // 발생한 이벤트를 대기 + for (int i = 0; i < newEvents; i++) { + if (eventList[i].ident == (uintptr_t)serverSocket) { + // 새로운 연결 수락 + sockaddr_in clientAddress; + socklen_t clientAddressLength = sizeof(clientAddress); + int clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &clientAddressLength); + if (clientSocket < 0) + continue; // 연결 수락 실패 + + // 클라이언트 소켓에 대한 읽기 이벤트 등록 + EV_SET(&changeEvent, clientSocket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); + if (kevent(kq, &changeEvent, 1, NULL, 0, NULL) == -1) { + cout << "클라이언트 소켓 kevent 등록 실패" << endl; + close(clientSocket); + } + } else if (eventList[i].filter == EVFILT_READ) { + // 클라이언트로부터 데이터 읽기 + httpHandler(eventList[i].ident); + + } + } + } +} diff --git "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/server.cpp" "b/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/server.cpp" deleted file mode 100644 index 605ecea..0000000 --- "a/assignment/network/http/simple_webserver/\354\247\200\354\204\240\354\235\230/server.cpp" +++ /dev/null @@ -1,178 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -//int PORT = 8080; -const int BUFFER_SIZE = 1024; - -#define HEADER_FMT "HTTP/1.1 %d %s\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n" -#define NOT_FOUND_CONTENT "404 Not Found" -#define SERVER_ERROR_CONTENT "500 Internal Server Error" - -using namespace std; - -void httpHandler(int acceptSocket); -void fill_header(char *header, int status, long len, char *type); -void find_mime(char *ct_type, char *uri); -void handle_404(int acceptSocket); -void handle_500(int acceptSocket); - -int main(int argc, char **argv){ - struct sockaddr_in remote_sin; - int PORT, pid; - - if(argc < 2){ - cout<<"Usage"< 0){ //파일에서 데이터를 읽어와서 클라이언트에게 전송하는데, 파일의 내용을 버퍼 사이즈만큼 읽고 읽은 데이터를 클라이언트에게 전송 - write(acceptSocket, buf, cnt); - } - -} - -//http 해더 형식 지정 함수 -void fill_header(char *header, int status, long len, char *type){ - char status_text[40]; //http응답 상태 코드에 해당하는 텍스트 저장 - switch(status){ - case 200: - strcpy(status_text,"OK"); //status_text에 적절한 텍스트 복사 - break; - case 404: - strcpy(status_text,"NOT FOUND"); - break; - case 500: - default : - strcpy(status_text,"Internet Server Error"); - break; - } - sprintf(header, HEADER_FMT, status, status_text, len, type); //header문자열에 http응답 헤더를 형식화해서 삽입 -} - -//uri에서 MIME 타입을 찾는 함수 -void find_mime(char *ct_type, char *uri){ - char *ext = strrchr(uri, '.'); - if(!strcmp(ext, ".html")){ - strcpy(ct_type, "text/html"); - } -} - -//404 에러 처리 -void handle_404(int acceptSocket){ - char header[BUFFER_SIZE]; - fill_header(header, 404, sizeof(NOT_FOUND_CONTENT), "text/html"); - write(acceptSocket, header, strlen(header)); -} - -//500 에러 처리 -void handle_500(int acceptSocket){ - char header[BUFFER_SIZE]; - fill_header(header, 500, sizeof(SERVER_ERROR_CONTENT), "text/html"); - write(acceptSocket, header, strlen(header)); -} \ No newline at end of file