情况:我正在用 C++ 实现一个用于管理本地网络上的计算机的程序。
问题:如何从客户端发送数据结构并在服务器程序上接收。请举个例子。也许有一个专门的图书馆,类似于
curl
互联网。
解决方案:事实证明,全球网络和本地网络并没有我想象的那么不同。对于解决方案,我将使用我自己的 C++ HTTP 服务器,您可以
curl
从浏览器访问它。
这是我在同一站点上找到并修改的服务器代码。程序接收到一个请求并从 index.html 文件中返回文本,如果它不存在,它会发送一个文件不存在的消息。感谢所有为这个问题做出贡献的人。
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
// Для корректной работы 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;
//Получить один из ІР первый попавшыйся
std::string GetIP()
{
std::string out = "WinSock ERR";
WSADATA wsaData;
if (!WSAStartup(WINSOCK_VERSION, &wsaData)){char chInfo[64];
if (!gethostname(chInfo, sizeof(chInfo)))
{
hostent *sh;
sh=gethostbyname((char*)&chInfo);
if (sh!=NULL)
{
int nAdapter = 0;
while (sh->h_addr_list[nAdapter])
{
struct sockaddr_in adr;
memcpy(&adr.sin_addr, sh->h_addr_list[nAdapter], sh->h_length);
out = inet_ntoa(adr.sin_addr);
nAdapter++;
}
}
}
}
WSACleanup();
return out;
}
//Получить фаил в формате строки
bool getFile(char* url,std::string &r)
{
r = "";
std::ifstream in(url);
if(in)
{
while(1)
{
char t;
in.get(t);
if(in.eof()) break;
r+=t;
}
in.close();
}
else
return false;
return true;
}
int main()
{
//char *a = (char*)x;
std::string sIP = GetIP();
std::cout<<sIP<<'\n';
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(sIP.c_str(), "80", &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";*/
std::string file;
std::string zp = buf;
//int Start = zp.find("GET");
//int End = zp.find("\n",Start);
//zp = zp.substr(Start,End);
//int pos = zp.find("comand=shutdownS",0);
//if(pos != std::string::npos)
//std::cout<<pos<<std::endl;
std::cout<<'\n'<<zp<<'\n';
if(getFile("index.html",file))
{
response_body<<file;
}
else
{
response_body << "<title>Test C++ HTTP Server</title>\n"
<< "<h1>No file index.html</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;
}
当我试图找出代码时,我总是删除不必要的检查,因为这里是没有检查的代码
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
// Для корректной работы 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;
//Получить один из ІР первый попавшыйся
std::string GetIP()
{
std::string out = "WinSock ERR";
WSADATA wsaData;
if (!WSAStartup(WINSOCK_VERSION, &wsaData)){char chInfo[64];
if (!gethostname(chInfo, sizeof(chInfo)))
{
hostent *sh;
sh=gethostbyname((char*)&chInfo);
if (sh!=NULL)
{
int nAdapter = 0;
while (sh->h_addr_list[nAdapter])
{
struct sockaddr_in adr;
memcpy(&adr.sin_addr, sh->h_addr_list[nAdapter], sh->h_length);
out = inet_ntoa(adr.sin_addr);
nAdapter++;
}
}
}
}
WSACleanup();
return out;
}
int main()
{
//char *a = (char*)x;
std::string sIP = GetIP();
std::cout<<sIP<<'\n';
WSADATA wsaData; // служебная структура для хранение информации
// о реализации Windows Sockets
// старт использования библиотеки сокетов процессом
// (подгружается Ws2_32.dll)
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
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(sIP.c_str(), "80", &hints, &addr);
// Создание сокета
int listen_socket = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
// Если создание сокета завершилось с ошибкой, выводим сообщение,
// освобождаем память, выделенную под структуру addr,
// выгружаем dll-библиотеку и закрываем программу
// Привязываем сокет к IP-адресу
result = bind(listen_socket, addr->ai_addr, (int)addr->ai_addrlen);
// Инициализируем слушающий сокет
listen(listen_socket, SOMAXCONN);
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);
result = recv(client_socket, buf, max_client_buffer_size, 0);
std::stringstream response; // сюда будет записываться ответ клиенту
std::stringstream response_body; // тело ответа
if (result > 0) {
// Мы знаем фактический размер полученных данных, поэтому ставим метку конца строки
// В буфере запроса.
buf[result] = '\0';
std::string file;
std::string zp = buf;
std::cout<<'\n'<<zp<<'\n';
//напечатать ответ
response_body << "<title>Test C++ HTTP Server</title>\n"
<< "<h1>Hello server C++</h1>\n"
<< "<p>This is body of the test page...</p>\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);
// Закрываем соединение к клиентом
closesocket(client_socket);
}
}
// Убираем за собой
closesocket(listen_socket);
freeaddrinfo(addr);
WSACleanup();
return 0;
}
程序在启动时会在控制台中显示 IP 地址,必须在浏览器中输入该地址。如果您在本地网络上并且程序获取网络连接的适配器的地址,无论是 Wi-Fi 还是有线,本地网络上的任何计算机都可以发送请求并接收响应从你的程序。有个不知道怎么修复的bug,有时候页面加载时间长,没有收到响应,但是如果重新加载,响应立马就来了。
您可以使用网络
C++
库组件中最流行的网络选项之一。boost
另外,在这里,如果由于某种原因它不起作用,您一定可以找到合适的库来解决您的问题
boost
。