/** * В.Д.Валединский * Простейший пример HTTP сервера. * * Файлы * ser_tcp_select.cpp - пример TCP сервера c использованием select() * * Сервер получает HTTP запрос и возвращает простейший HTML файл * либо отказ, если запрашивается не index.html * */ #include "stdafx.h" #pragma warning(suppress : 4996) #pragma comment(lib, "Ws2_32.lib") #define _WINSOCK_DEPRECATED_NO_WARNINGS #include #include #include #include #include #include #include #include using namespace std; #include #include // Определимся с номером порта и другими константами. #define PORT 5555 #define BUFLEN 4096 // Две вспомогательные функции для чтения/записи (см. ниже) int readFromClientHTTP(int fd, char *buf); int writeToClientHTTP(int fd, char *buf); int writeToClientHTTPForm(int fd, char *buf); int main(void) { int i, err, opt = 1; int sock, new_sock; fd_set active_set, read_set; struct sockaddr_in addr; struct sockaddr_in client; char buf[BUFLEN]; socklen_t size; printf("http SERVER\n"); // Инициализация windows sockets WSADATA wsaData; if ( WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed\n"); return 1; } // Создаем TCP сокет для приема запросов на соединение sock = socket(PF_INET, SOCK_STREAM, 0); if (sock<0) { perror("Server: cannot create socket"); exit(EXIT_FAILURE); } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)); // Заполняем адресную структуру и // связываем сокет с любым адресом addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); err = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); if (err<0) { perror("Server: cannot bind socket"); WSACleanup(); exit(EXIT_FAILURE); } // Создаем очередь на 3 входящих запроса соединения err = listen(sock, 3); if (err<0) { perror("Server: listen queue failure"); WSACleanup(); exit(EXIT_FAILURE); } // Подготавливаем множества дескрипторов каналов ввода-вывода. // Для простоты не вычисляем максимальное значение дескриптора, // а далее будем проверять все дескрипторы вплоть до максимально // возможного значения FD_SETSIZE. FD_ZERO(&active_set); FD_SET(sock, &active_set); // Основной бесконечный цикл проверки состояния сокетов while (1) { // Проверим, не появились ли данные в каком-либо сокете. // В нашем варианте ждем до фактического появления данных. read_set = active_set; int nset; if ( (nset = select(FD_SETSIZE, &read_set, NULL, NULL, NULL)) < 0) { perror("Server: select failure"); WSACleanup(); exit(EXIT_FAILURE); } // fd_set в windows устроена немного иначе - как массив дескрипторов for (int j = 0; j < active_set.fd_count; j++) { printf("active set[%d] socket %d\n", j, active_set.fd_array[j]); } for (int j = 0; j < read_set.fd_count; j++) { printf("read set[%d] socket %d\n", j, read_set.fd_array[j]); } // Данные появились. Проверим в каком сокете. //for (int j = 0; j\r\n"; html << "\r\n"; html << "\r\n"; html << "\r\n"; html << "Учебный сервер\r\n"; html << "\r\n"; html << "\r\n"; html << "

МГУ им М.В.Ломоносова

\r\n"; html << "

Просто абзац текста

\r\n"; html << "\r\n"; html << "\r\n"; http << "HTTP/1.1 200 OK\r\n"; http << "Connection: keep-alive\r\n"; http << "Content-type: text/html\r\n"; http << "Content-length: " << html.str().length() << "\r\n"; http << "\r\n"; http << html.str(); ret = 0; } else { http << "HTTP/1.1 404 Not found\r\n"; http << "Connection: close\r\n"; http << "Content-type: image/png\r\n"; http << "Content-length: 0\r\n"; http << "\r\n"; ret = -1; } nbytes = send(fd, http.str().c_str(), http.str().length() + 1, 0); if (nbytes < 0) ret = -1; printf("write ret %d\n", ret); return ret; } int writeToClientHTTPForm(int fd, char *buf) { int nbytes, ret; stringstream http; stringstream html; bool ok1, ok2; char *p = strstr(buf, "index.html"); char *q = strstr(buf, "=Send"); ok1 = p && p - buf < 20; ok2 = q != 0; if ( ok1 || ok2 ) { html << "\r\n"; html << "\r\n"; html << "\r\n"; html << "\r\n"; html << "Учебный сервер\r\n"; html << "\r\n"; html << "\r\n"; html << "

МГУ им М.В.Ломоносова

\r\n"; html << "
\r\n"; html << " request
\r\n"; html << " comment
\r\n"; html << " 1 \r\n"; html << " 2 \r\n"; html << " 3 \r\n"; html << " 4
\r\n"; html << " A \r\n"; html << " B \r\n"; html << " C
\r\n"; html << " \r\n"; html << "
\r\n"; html << "\r\n"; html << "\r\n"; http << "HTTP/1.1 200 OK\r\n"; http << "Connection: keep-alive\r\n"; http << "Content-type: text/html\r\n"; http << "Content-length: " << html.str().length() << "\r\n"; http << "\r\n"; http << html.str(); ret = 0; } else { http << "HTTP/1.1 404 Not found\r\n"; http << "Connection: close\r\n"; http << "Content-type: image/png\r\n"; http << "Content-length: 0\r\n"; http << "\r\n"; ret = -1; } nbytes = send(fd, http.str().c_str(), http.str().length() + 1, 0); if (nbytes < 0) ret = -1; printf("write ret %d\n",ret); return ret; }