Я пытался передать файл 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;
}
Я точно не ожидал этой ошибки после просмотра страницы на долю секунды.
Для HTTP/1.1 вам необходимо отправить заголовок Connection: close, если вы хотите закрыть соединение.
Кроме того, проверили ли вы, что происходит на сервере, когда вы получаете эту ошибку на клиенте?
Примечание. Вы не можете сказать «Отправлено «Привет» клиенту». если bytesSent != SOCKET_ERROR
. Возвращаемое значение send
— это SOCKET_ERROR
или количество байтов, записанных в буфер передачи. Последнее может быть, а может и не быть всем сообщением, которое вы намеревались отправить, если буфер передачи заполнится. Хуже того, данные в буфере отправки могут никогда не быть успешно отправлены по множеству причин, о которых send
невозможно вам рассказать, поскольку работа send
заканчивается, когда данные ставятся в очередь для отправки. Очень привередливая штука — сетевое программирование.
Серверу необходимо сообщить клиенту, как он должен узнать, что ответ полностью получен. Наиболее распространенными являются заголовок Content-Length
, если сервер заранее знает размер, или Transfer-Encoding: chunked
, если сервер не знает. Для совместимости с HTTP/1.0 сервер может указать заголовок Connection: close
, а затем просто закрыть соединение в конце ответа; это не рекомендуется, поскольку в этом случае клиент не сможет определить, пришел ли ответ полностью или соединение прервалось на полпути, и может ошибочно интерпретировать неполный ответ как успешный.
Спасибо, ребята, за ответы, проблема заключалась в отсутствующих заголовках длины контента и кодировки передачи, и я проверю «bytesSent» в окончательной версии, я просто не включил его во время тестирования, спасибо всем ответам 👍
Проблема в том, что вы не сообщаете клиенту (браузеру), когда ответ будет завершен. Вы ДОЛЖНЫ отправить либо:
заголовок 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: Длина тела сообщения.
Отлично, да, сработало, спасибо
Кроме того, я пробовал без closesocket, я пробовал без цикла while (только один клиент), я пробовал использовать потоки, ни один из них не работал