c++firefoxserverlocalhost

Serving html using C++ - loading page error


I was trying to serve an index.html file from the current directory (I changed it to just "Hello" for testing purposes). I see the page for a split second and then it just gives me this:

The connection was reset

The connection to the server was reset while the page was loading.

The site could be temporarily unavailable or too busy. Try again in a few moments.
If you are unable to load any pages, check your computer’s network connection.
If your computer or network is protected by a firewall or proxy, make sure that Firefox is permitted to access the web.

I did try everything they suggested, didn't work, and I can't get enough docs about this specific topic.

Here's the 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;
}

I sure didn't expect this error after seeing the page for a split second.


Solution

  • The problem is that you are not telling the client (browser) when the response is finished. You MUST send either:

    Also, since you are closing the socket after sending the response, you should send a Connection: close header so the client knows to close their end of the connection when the response is finished.

    Also, send() is not guaranteed to send as many bytes as you ask, it may send less, so you need to call send() in a loop until all bytes are actually sent.

    Try something more like this:

    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);
    }
    

    Read the HTTP 1.1 protocol spec, RFC 2616, and its successors RFCs 7230, 7231, 7232, 7233, 7234, and 7235. Pay particular attention to RFC 2616 Section 4.4: Message Length and RFC 7230 Section 3.3.3: Message Body Length.