Я пытался передать файл index.html
из текущего каталога (в целях тестирования я изменил его на "Hello"
). Я вижу страницу на долю секунды, а потом она просто выдает мне это:
Соединение было сброшено
Соединение с сервером было сброшено во время загрузки страницы.
Возможно, сайт временно недоступен или слишком занят. Повторите попытку через несколько минут.
Если вам не удается загрузить какие-либо страницы, проверьте сетевое подключение вашего компьютера.
Если ваш компьютер или сеть защищены брандмауэром или прокси-сервером, убедитесь, что Firefox разрешен доступ к Интернету.
Я попробовал все, что они предложили, но не сработало, и я не могу получить достаточно документации по этой конкретной теме.
Вот server.cpp
:
#include <tchar.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <thread>
#include <string>
void handleClient(SOCKET acceptSocket) {
std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello";
int bytesSent = send(acceptSocket, response.c_str(), response.size(), 0);
if (bytesSent == SOCKET_ERROR) {
std::cerr << "Error sending data to client: " << WSAGetLastError() << std::endl;
} else {
std::cout << "Served 'Hello' to client." << std::endl;
}
closesocket(acceptSocket);
}
int main() {
SOCKET serverSocket, acceptSocket;
const int PORT = 55555;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
std::cerr << "Winsock dll not found." << std::endl;
return 0;
} else {
std::cout << "Winsock dll was found!" << std::endl;
std::cout << "Status: " << wsaData.szSystemStatus << std::endl;
}
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Error at socket()." << std::endl;
WSACleanup();
return 0;
} else {
std::cout << "Socket() is OK!" << std::endl;
}
sockaddr_in service;
service.sin_family = AF_INET;
InetPton(AF_INET, _T("127.0.0.1"), &service.sin_addr.s_addr);
service.sin_port = htons(PORT);
if (bind(serverSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) {
std::cerr << "bind() failed." << std::endl;
std::cerr << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 0;
} else {
std::cout << "bind() is OK!" << std::endl;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "listen() error listening on socket." << std::endl;
closesocket(serverSocket);
WSACleanup();
return 0;
} else {
std::cout << "listen() is OK!, waiting for connections.." << std::endl;
}
while (true) {
acceptSocket = accept(serverSocket, NULL, NULL);
if (acceptSocket == INVALID_SOCKET) {
std::cerr << "accept failed." << std::endl;
std::cerr << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return -1;
}
std::cout << "Client connected.." << std::endl;
handleClient(acceptSocket);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
Я точно не ожидал этой ошибки после просмотра страницы на долю секунды.
🤔 А знаете ли вы, что...
C++ позволяет создавать пользовательские типы данных с использованием классов и структур.
Проблема в том, что вы не сообщаете клиенту (браузеру), когда ответ будет завершен. Вы ДОЛЖНЫ отправить либо:
заголовок Content-Length
, указывающий фактическое количество отправляемых байтов.
заголовок Transfer-Encoding: chucked
, за которым следуют фрагменты данных, завершающиеся фрагментом длиной 0.
Кроме того, поскольку вы закрываете сокет после отправки ответа, вам следует отправить заголовок Connection: close
, чтобы клиент знал, что нужно закрыть свой конец соединения после завершения ответа.
Кроме того, send()
не гарантированно отправит столько байтов, сколько вы запрашиваете, он может отправить меньше, поэтому вам нужно вызывать send()
в цикле, пока все байты не будут фактически отправлены.
Попробуйте еще что-нибудь вроде этого:
void handleClient(SOCKET acceptSocket) {
std::string response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 5\r\n" // <-- ADD THIS!
"Connection: close\r\n" // <-- ADD THIS!
"\r\n"
"Hello";
const char *data = response.c_str();
size_t size = response.size();
while (size > 0) {
int bytesSent = send(acceptSocket, data, size, 0);
if (bytesSent == SOCKET_ERROR) {
int err = WSAGetLastError();
std::cerr << "Error sending data to client: " << err << std::endl;
break;
}
data += bytesSent;
size -= bytesSent;
}
if (size == 0)
std::cout << "Served 'Hello' to client." << std::endl;
closesocket(acceptSocket);
}
Прочтите спецификацию протокола HTTP 1.1, RFC 2616 и его преемников RFC 7230 , 7231 , 7232 , 7233 , 7234 и 7235. Обратите особое внимание на RFC 2616, раздел 4.4: Длина сообщения и RFC 7230, раздел 3.3.3: Длина тела сообщения.