#include #include #include #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); void writeToClientHTTP(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"); exit(EXIT_FAILURE); } // Создаем очередь на 3 входящих запроса соединения err = listen(sock, 3); if (err<0) { perror("Server: listen queue failure"); exit(EXIT_FAILURE); } // Подготавливаем множества дескрипторов каналов ввода-вывода. // Для простоты не вычисляем максимальное значение дескриптора, // а далее будем проверять все дескрипторы вплоть до максимально // возможного значения FD_SETSIZE. FD_ZERO(&active_set); FD_SET(sock, &active_set); // Основной бесконечный цикл проверки состояния сокетов while (1) { // Проверим, не появились ли данные в каком-либо сокете. // В нашем варианте ждем до фактического появления данных. read_set = active_set; if ( select(FD_SETSIZE, &read_set, NULL, NULL, NULL) < 0) { perror("Server: select failure"); exit(EXIT_FAILURE); } // fd_set в windows устроена немного иначе - как массив дескрипторов // Данные появились. Проверим в каком сокете. for (int j = 0; j void ProcessHTML(stringstream &html, string & request) { /* char tbuf[64]; // время, когда обрабатываем этот запрос time_t ttt; // можем потом поставить в заголовок ответа сервера time(&ttt); ctime_s(tbuf, 256, &ttt); printf("%s\n",tbuf); */ // генерируем выходной html // здесь request не влияет на выводимый html, но это нетрудно поменять 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 << " 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"; } // простейший разбор запроса и отправление ответа void writeToClientHTTP(int fd, char *buf) { int nbytes; stringstream head; stringstream html; string request = ""; // строка параметров запроса if (strstr(buf, "GET")) { // здесь параметры в первой строке после / char *p1 = strchr(buf, '/'); char *p2 = strchr(p1, ' '); *p2 = 0; request = p1; printf("get request: %s\n", request.c_str()); *p2 = ' '; } if (strstr(buf, "POST")) { // здесь параметры после всего заголовка после пустой строки char *p1 = strstr(buf, "\r\n\r\n"); request = (p1 + 4); printf("post request: %s\n", request.c_str()); } // ответ на нераспознанные запросы // не совсем аккуратно, чтобы не загромождать ... // отбрасывает непустые GET запросы, в которых нет параметра "request" if (request != "/" && request.find("request") == string::npos) { head << "HTTP/1.1 404 Not found\r\n"; head << "Connection: close\r\n"; head << "Content-length: 0\r\n"; head << "\r\n"; nbytes = send(fd, head.str().c_str(), head.str().length() + 1, 0); return; } // ответ на распознанные запросы // формирование HTML ProcessHTML(html, request); int html_length = html.str().length(); // формирование HTTP заголовка head << "HTTP/1.1 200 OK\r\n"; head << "Connection: keep-alive\r\n"; head << "Content-type: text/html\r\n"; head << "Content-length: " << html_length << "\r\n"; head << "\r\n"; // вывод заголовка и html nbytes = send(fd, head.str().c_str(), head.str().length() + 1, 0); printf("http nb = %d\n", nbytes); nbytes = send(fd, html.str().c_str(), html.str().length() + 1, 0); printf("html nb = %d\n", nbytes); // для контроля того, что отправили //cout << "Write back\n"; //cout << head.str(); //cout << html.str(); if (nbytes<0) { perror("Server: write failure"); } }