I am trying to do this article, I dug up Google, but I didn’t find anything sensible (or just don’t know how to formulate queries on this topic correctly)

How can I get the ip address of the connected client?

Here is the copied code from the article:

#include <iostream> #include <sstream> #include <string> // Для корректной работы freeaddrinfo в MinGW #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; } 

    1 answer 1

    Find the accept function. This feature is used to accept a request from a client to establish a connection with a server. In your example, the second and third parameters are NULL. Namely, they must be used to accept customer data.

     sockaddr_in cs_addr; //или SOCKADDR_IN cs_addr; socklen_t cs_addrsize = sizeof (cs_addr); //или int cs_addrsize = sizeof(cs_addr); client_socket = accept(listen_socket, (struct sockaddr *) &cs_addr, &cs_addrsize); 

    The cs_addr.sin_addr 's ip-address will be stored in cs_addr.sin_addr . The string is provided using inet_ntoa .

    • Thanks, it works. - Fangog
    • Once you understand, I would like to ask more advice. If I am going to process clients in streams, I correctly understand that after accept I will create a stream? Sending a copy of client_socket to it, and then all the code that is lower in the cycle will be processed by the stream - Fangog
    • @Fangog get yourself a book Sneijder ozon.ru/context/detail/id/126048 - many questions will disappear. - gbg
    • @Fangog Yes. You understand correctly if you are going to process clients in streams. But keep in mind that creating threads is quite a time consuming operation (and switching between them is also not free) in terms of resources. Therefore, the creation of a separate stream for each client is a matter of expediency. With some tests, with a small number of clients, with a low load, this approach can be justified in order to simplify readability and understanding of the code. But if you do something serious, then this approach will be wrong. - Max ZS
    • one
      @Fangog The approach you described in your last comment looks more correct than creating a separate stream for each connection (as described earlier). With this approach, the only thing that seems redundant is an attempt to balance the load flow. How to define it is another question. After all, a large number of connections in the stream absolutely does not mean that it performs more work (maybe the connections are idle). Therefore, the connections are simply scattered in order and evenly. And the system will already deal with loading and distributing threads among the processor cores. - Max ZS