繁体   English   中英

C++ 多线程 HTTP 服务器 - recv() 在第一次发送第一个响应后挂断

[英]C++ multithread HTTP Server - recv() hangs up after first sending first response

I'm trying to build a multithread HTTP server using C++ and winsock2.h and sys/socket.h.However, after sending response successfully to first request, accept() function captures other requests and sends through thread pool but those threads hangs up在 recv() function 所以 function 永远无法从套接字捕获数据。这是我的代码。

void HTTPServer::init()
{

#ifdef _WIN32
    WSADATA wsaData;
    WSAStartup(0x202,&wsaData);

    if((mSock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
#else
    if((mSock = socket(AF_INET,SOCK_STREAM,0)) < 0)
#endif
    {
        std::cout << "Error while initilazing socket\n";
    }

    mServerAddr.sin_family = AF_INET;
    mServerAddr.sin_port = htons(mPort);
#ifdef _WIN32
    mServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;
#else
    mServerAddr.sin_addr.S_addr = INADDR_ANY;
#endif

    if(bind(mSock, (struct sockaddr*) &mServerAddr, sizeof(mServerAddr)) < 0)
    {
        std::cout << "Error while binding socket\n";
    }

    if(listen(mSock, SOMAXCONN))
    {
        std::cout << "Error while listening socket\n";
    }

}
void HTTPServer::fRun()
{
    ThreadPool* tPool = new ThreadPool(10);
    while(1)
    {
        int size = sizeof(mClientAddr);
#ifdef _WIN32
        if((mAcceptSocket = accept(mSock,(struct sockaddr*) &mClientAddr,&size)) == INVALID_SOCKET)
#else
        if((mAcceptSocket = accept(mSock,(struct sockaddr*) &mClientAddr,&size))) < 0)
#endif
        {
            std::cout << "Error while initilazing accept socket\n";
        }

    
        std::cout << "Socket Sent " << mAcceptSocket << std::endl;
        tPool->enqueue([&] { this->fOnRequest(mAcceptSocket); });

    }
    delete tPool;
}
void HTTPServer::fOnRequest(uint64_t socket)
{
    const string reqData = fRecieveNext(mAcceptSocket);
    const HTTPResponse res = fProcessRequest(reqData);
    fSendResponse(res,socket);
    std::cout << "Done";
}
const string HTTPServer::fRecieveNext(uint64_t socket)
{
    int64_t recieveLength = 0,totalRecieved = 0; 
    int64_t recieveLengthBeforeBody = -1;
    int contentLength = 0;
    string rawData;
    while(1)
    {
        memset(mBuffer,'\0',8192);

        if((recieveLength = recv(socket,mBuffer,8192, 0)) == SOCKET_ERROR)
        {
            std::cout << "Error while receiving data from socket\n";
#ifdef _WIN32
            std::cout << WSAGetLastError() << std::endl;
#endif
            break;
        }


        if(recieveLength == 0)
            break;
        
        totalRecieved += recieveLength; 
        rawData += string(mBuffer,recieveLength);

        if(totalRecieved > 32)
        {
            if(rawData.find("Content-Length") == string::npos && contentLength == 0)
                break;
            else
            {
                if(contentLength == 0)
                {
                    auto pos = rawData.find("Content-Length:");
                    auto lengthStr = rawData.substr(pos + 16, rawData.find_first_of("\r",pos) - pos - 16);
                    contentLength = std::stoi(lengthStr);
                }
                if(rawData.find("\r\n\r\n") != string::npos && recieveLengthBeforeBody == -1)
                {
                    recieveLengthBeforeBody = rawData.find("\r\n\r\n") + 4;
                }

                if(totalRecieved >= contentLength + recieveLengthBeforeBody)
                    break;
            }
        }
    }

    return rawData;
}
void HTTPServer::fSendResponse(const HTTPResponse& response,const uint64_t socket)
{
    string resStr = response.fSerializeResponse();
    size_t sent = 0,totalSent = 0;
    char* buffer = &(resStr[0]);

    while(totalSent < resStr.length())
    {
        if((sent = send(socket, buffer, resStr.length() - totalSent,0)) < 0)
        {
            std::cout << "Error while sending response" << std::endl;
        }

        
        buffer += sent;
        totalSent += sent;
    }

    delete &response;
#ifdef _WIN32
    if(shutdown(socket, SD_BOTH) == SOCKET_ERROR)
    {
        std::cout << "Error while closing socket" << std::endl;
        std::cout << WSAGetLastError() << std::endl;
    };
    if(closesocket(socket) == SOCKET_ERROR)
    {
        std::cout << "Error while closing socket" << std::endl;
        std::cout << WSAGetLastError() << std::endl;
    };
#else
    if(shutdown(socket, SHUT_RDWR) < 0)
    {
        std::cout << "Error while closing socket" << std::endl;
    };
    if(close(socket) < 0)
    {
        std::cout << "Error while closing socket" << std::endl;
    };
#endif

}

看起来您希望在一次接收中收到一条 TCP 消息。 TCP 不能那样工作。 Tcp 是一个 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 协议,发送给你的消息可以分成多个块。 TCP 只保证字节会以正确的顺序到达一次。

这会让你与输入不同步

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM