MIPI_AdvancedC_FRTK/Seminar1/Windows/http_server_v2.1.cpp
2024-11-14 08:45:50 +03:00

164 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <sstream>
#include <string>
//http://127.0.0.1:8000/
// Для корректной работы freeaddrinfo в MinGW
// Подробнее: http://stackoverflow.com/a/20306451
#define _WIN32_WINNT 0x501
#include <WinSock2.h>
#include <WS2tcpip.h>
// Необходимо, чтобы линковка происходила с DLL-библиотекой
// Для работы с сокетам
#pragma comment(lib, "Ws2_32.lib")
using std::cerr;
int main()
{
WSADATA wsaData; // служебная структура для хранение информации
// о реализации Windows Sockets
// старт использования библиотеки сокетов процессом
// (подгружается Ws2_32.dll)
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
// Если произошла ошибка подгрузки библиотеки
if (result != 0) {
cerr << "WSAStartup failed: " << result << "\n";
return result;
}
struct addrinfo* addr = NULL; // структура, хранящая информацию
// об IP-адресе слущающего сокета
// Шаблон для инициализации структуры адреса
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // AF_INET определяет, что будет
// использоваться сеть для работы с сокетом
hints.ai_socktype = SOCK_STREAM; // Задаем потоковый тип сокета
hints.ai_protocol = IPPROTO_TCP; // Используем протокол TCP
hints.ai_flags = AI_PASSIVE; // Сокет будет биндиться на адрес,
// чтобы принимать входящие соединения
// Инициализируем структуру, хранящую адрес сокета - addr
// Наш HTTP-сервер будет висеть на 8000-м порту локалхоста
result = getaddrinfo("127.0.0.1", "8000", &hints, &addr);
// Если инициализация структуры адреса завершилась с ошибкой,
// выведем сообщением об этом и завершим выполнение программы
if (result != 0) {
cerr << "getaddrinfo failed: " << result << "\n";
WSACleanup(); // выгрузка библиотеки Ws2_32.dll
return 1;
}
// Создание сокета
int listen_socket = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
// Если создание сокета завершилось с ошибкой, выводим сообщение,
// освобождаем память, выделенную под структуру addr,
// выгружаем dll-библиотеку и закрываем программу
if (listen_socket == INVALID_SOCKET) {
cerr << "Error at socket: " << WSAGetLastError() << "\n";
freeaddrinfo(addr);
WSACleanup();
return 1;
}
// Привязываем сокет к IP-адресу
result = bind(listen_socket, addr->ai_addr, (int)addr->ai_addrlen);
// Если привязать адрес к сокету не удалось, то выводим сообщение
// об ошибке, освобождаем память, выделенную под структуру addr.
// и закрываем открытый сокет.
// Выгружаем DLL-библиотеку из памяти и закрываем программу.
if (result == SOCKET_ERROR) {
cerr << "bind failed with error: " << WSAGetLastError() << "\n";
freeaddrinfo(addr);
closesocket(listen_socket);
WSACleanup();
return 1;
}
// Инициализируем слушающий сокет
if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR) {
cerr << "listen failed with error: " << WSAGetLastError() << "\n";
closesocket(listen_socket);
WSACleanup();
return 1;
}
const int max_client_buffer_size = 1024;
char buf[max_client_buffer_size];
int client_socket = INVALID_SOCKET;
for (;;) {
// Принимаем входящие соединения
client_socket = accept(listen_socket, NULL, NULL);
if (client_socket == INVALID_SOCKET) {
cerr << "accept failed: " << WSAGetLastError() << "\n";
closesocket(listen_socket);
WSACleanup();
return 1;
}
result = recv(client_socket, buf, max_client_buffer_size, 0);
std::stringstream response; // сюда будет записываться ответ клиенту
std::stringstream response_body; // тело ответа
if (result == SOCKET_ERROR) {
// ошибка получения данных
cerr << "recv failed: " << result << "\n";
closesocket(client_socket);
} else if (result == 0) {
// соединение закрыто клиентом
cerr << "connection closed...\n";
} else if (result > 0) {
// Мы знаем фактический размер полученных данных, поэтому ставим метку конца строки
// В буфере запроса.
buf[result] = '\0';
// Данные успешно получены
// формируем тело ответа (HTML)
response_body << "<title>Test C++ HTTP Server</title>\n"
<< "<h1>Test page</h1>\n"
<< "<p>This is body of the test page...</p>\n"
<< "<h2>Request headers</h2>\n"
<< "<pre>" << buf << "</pre>\n"
<< "<em><small>Test C++ Http Server</small></em>\n";
// Формируем весь ответ вместе с заголовками
response << "HTTP/1.1 200 OK\r\n"
<< "Version: HTTP/1.1\r\n"
<< "Content-Type: text/html; charset=utf-8\r\n"
<< "Content-Length: " << response_body.str().length()
<< "\r\n\r\n"
<< response_body.str();
// Отправляем ответ клиенту с помощью функции send
result = send(client_socket, response.str().c_str(),
response.str().length(), 0);
if (result == SOCKET_ERROR) {
// произошла ошибка при отправле данных
cerr << "send failed: " << WSAGetLastError() << "\n";
}
// Закрываем соединение к клиентом
closesocket(client_socket);
}
}
// Убираем за собой
closesocket(listen_socket);
freeaddrinfo(addr);
WSACleanup();
return 0;
}