2017-08-15 60 views
-1

我正在嘗試創建http服務器。這導致該代碼從服務器沒有到達的響應C++

using namespace std; 
// Need to link with Ws2_32.lib 
#pragma comment (lib, "Ws2_32.lib") 
// #pragma comment (lib, "Mswsock.lib") 

#define DEFAULT_BUFLEN 512 
#define DEFAULT_PORT "8080" 

int __cdecl main(void) 
{ 

    std::stringstream wsss; 
    wsss << "HTTP/1.1 200 OK\r\n" 
     << "Connection: keep-alive\r\n" 
     << "Content-Type: Content-Type: text/html\r\n" 
     << "Content-Length: 5\r\n" 
     << "Ahoj\r\n"; 
    string tmp = wsss.str(); 
    const char * cstr = tmp.c_str(); 

    WSADATA wsaData; 
    int iResult; 

    SOCKET ListenSocket = INVALID_SOCKET; 
    SOCKET ClientSocket = INVALID_SOCKET; 

    struct addrinfo *result = NULL; 
    struct addrinfo hints; 

    int iSendResult; 
    char recvbuf[DEFAULT_BUFLEN]; 
    int recvbuflen = DEFAULT_BUFLEN; 

    // Initialize Winsock 
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (iResult != 0) { 
     printf("WSAStartup failed with error: %d\n", iResult); 
     return 1; 
    } 

    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 
    hints.ai_flags = AI_PASSIVE; 

    // Resolve the server address and port 
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
    if (iResult != 0) { 
     printf("getaddrinfo failed with error: %d\n", iResult); 
     WSACleanup(); 
     return 1; 
    } 

    // Create a SOCKET for connecting to server 
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
    if (ListenSocket == INVALID_SOCKET) { 
     printf("socket failed with error: %ld\n", WSAGetLastError()); 
     freeaddrinfo(result); 
     WSACleanup(); 
     return 1; 
    } 

    // Setup the TCP listening socket 
    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
    if (iResult == SOCKET_ERROR) { 
     printf("bind failed with error: %d\n", WSAGetLastError()); 
     freeaddrinfo(result); 
     closesocket(ListenSocket); 
     WSACleanup(); 
     return 1; 
    } 

    freeaddrinfo(result); 

    iResult = listen(ListenSocket, SOMAXCONN); 
    if (iResult == SOCKET_ERROR) { 
     printf("listen failed with error: %d\n", WSAGetLastError()); 
     closesocket(ListenSocket); 
     WSACleanup(); 
     return 1; 
    } 

    // Accept a client socket 
    cout << "Starting to listen " << endl; 
    ClientSocket = accept(ListenSocket, NULL, NULL); 
    if (ClientSocket == INVALID_SOCKET) { 
     printf("accept failed with error: %d\n", WSAGetLastError()); 
     closesocket(ListenSocket); 
     WSACleanup(); 
     return 1; 
    } 
    cout << "Listening " << endl; 
    // No longer need server socket 
    //closesocket(ListenSocket); 

    // Receive until the peer shuts down the connection 
    do { 

     iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 
     if (iResult > 0) { 
      printf("Bytes received: %d\n", iResult); 
      cout << recvbuf << endl; 
      // Echo the buffer back to the sender 
      iSendResult = send(ClientSocket, cstr , iResult, 0); 
      if (iSendResult == SOCKET_ERROR) { 
       printf("send failed with error: %d\n", WSAGetLastError()); 
       closesocket(ClientSocket); 
       WSACleanup(); 
       return 1; 
      } 
      printf("Bytes sent: %d\n", iSendResult); 
      cout << " === " << endl; 
     } 
     else if (iResult == 0) { 
      printf("Connection closing11...\n"); 
     } 
     else { 
      printf("recv failed with error: %d\n", WSAGetLastError()); 
      closesocket(ClientSocket); 
      WSACleanup(); 
      return 1; 
     } 

    } while (iResult > 0); 


    // shutdown the connection since we're done 
    iResult = shutdown(ClientSocket, SD_SEND); 
    if (iResult == SOCKET_ERROR) { 
     printf("shutdown failed with error: %d\n", WSAGetLastError()); 
     closesocket(ClientSocket); 
     WSACleanup(); 
     return 1; 
    } 

    // cleanup 
    closesocket(ClientSocket); 
    WSACleanup(); 

    return 0; 
} 

但是,當我嘗試使用郵遞員,它不寫 目前在Windows上我發現一些材料「開始聽」 「聽」 顯示get請求 發送的字節數: 431

然後停止。客戶端沒有收到任何東西,因此服務器仍然在運行(應該在1次連接後關閉)。

我一直未能找到它表現爲這樣的w/e任何錯誤的原因。 我使用Visual Studio 2015. 所有幫助表示讚賞。 謝謝。

+0

http://samuel-beckett.net/Waiting_for_Godot_Part1.html – user0042

+0

請在** minimal **上創建[MCVE]重點** – bolov

+0

我不明白爲什麼您希望單個應用程序運行單個應用程序,並使用阻止調用來充當服務器及其客戶端。 –

回答

3

你的代碼有很多問題。

  • 你的HTTP響應誤格式化:

    • Content-Type頭的格式不正確。 (或6)而不是5

    • 您在Content-Length: ...\r\n 之前和Ahoj之前缺少額外的所需\r\n。 HTTP頭由\r\n\r\n終止。

    • \r\nAhoj需要被刪除,除非您增加Content-Length至6

    • 保持HTTP連接進行談判,所以不要盲目地在回信一個Connection: keep-alive頭。您必須檢查客戶端是否發送帶有Connection: keep-alive標頭的HTTP 1.0請求,或者是否不帶Connection: close標頭的HTTP 1.1請求,然後相應地執行操作。除非客戶要求您這樣做,否則不要保持連接活動,並且您同意這樣做。請確保將Connection響應標頭相應地設置爲您實際使用套接字執行的操作。

  • 您沒有正確處理客戶端請求。

    首先,recv()不會返回以空字符結尾的數據,但您的cout語句假定它有。您需要將輸出限制爲由recv()報告的實際字節數。使用cout.write()代替cout << ...

    但是,更重要的是,您根本沒有實際解析客戶端的HTTP請求。當客戶端發送任何任意數據(不是有效的HTTP請求),你要發送的HTTP響應,但你的send()len參數設置爲從客戶端讀取的字節數,而不是數量你的迴應的字節。

    您必須正確解析客戶端的請求!特別是如果你尊重保活。首先閱讀最初的請求行,告訴你所請求的資源以及請求的HTTP版本。然後,逐行讀取請求標題,直到遇到結束標頭的\r\n\r\n序列。然後,您必須解析標題以確定IF是否存在請求主體,如何讀取它以及何時停止讀取它。有關這方面的具體細節,請參閱RFC 2616 Section 4.4 Message Length

    完整地讀完整個ENTIRE請求並進行驗證後,請發送您的響應(確保相應設置Connection響應標頭),然後關閉套接字(如果未請求保持活動狀態),否則返回並開始等待下一個請求到達。

  • send()可以發送比請求更少的字節,因此如果還有更多數據要發送,則需要檢查返回值並再次調用send()。您需要循環呼叫send(),直到完整發送完整的響應。

  • 「將緩衝區回送給發件人」對於HTTP服務器來說不是正確的做法。感覺就像你拿了一個ECHO服務器的例子,並且正在修改它的HTTP。 HTTP比ECHO實現起來要複雜得多。

隨着中說,嘗試更多的東西像這樣(未經測試,但應該給你什麼是參與一個想法):

有很多問題,你的代碼。

  • 你的HTTP響應誤格式化:

    • Content-Type頭的格式不正確。 (或6)而不是5

    • 您在Content-Length: ...\r\n 之前和Ahoj之前缺少額外的所需\r\n。 HTTP頭由\r\n\r\n終止。

    • \r\nAhoj需要被刪除,除非您增加Content-Length至6

    • 保持HTTP連接進行談判,所以不要盲目地在回信一個Connection: keep-alive頭。您必須檢查客戶端是否發送帶有Connection: keep-alive標頭的HTTP 1.0請求,或者是否不帶Connection: close標頭的HTTP 1.1請求,然後相應地執行操作。除非客戶要求您這樣做,否則不要保持連接活動,並且您同意這樣做。請確保將Connection響應標頭相應地設置爲您實際使用套接字執行的操作。

  • 您沒有正確處理客戶端請求。

    首先,recv()不會返回以空字符結尾的數據,但您的cout語句假定它有。您需要將輸出限制爲由recv()報告的實際字節數。使用cout.write()代替cout << ...

    但是,更重要的是,您根本沒有實際解析客戶端的HTTP請求。當客戶端發送任何任意數據(不是有效的HTTP請求),你要發送的HTTP響應,但你的send()len參數設置爲從客戶端讀取的字節數,而不是數量你的迴應的字節。

    您必須正確解析客戶端的請求!特別是如果你尊重保活。首先閱讀最初的請求行,告訴你所請求的資源以及請求的HTTP版本。然後,逐行讀取請求標題,直到遇到結束標頭的\r\n\r\n序列。然後,您必須解析標題以確定IF是否存在請求主體,如何讀取它以及何時停止讀取它。有關這方面的具體細節,請參閱RFC 2616 Section 4.4 Message Length

    完整地讀完整個ENTIRE請求並進行驗證後,請發送您的響應(確保相應設置Connection響應標頭),然後關閉套接字(如果未請求保持活動狀態),否則返回並開始等待下一個請求到達。

  • send()可以發送比請求更少的字節,因此如果還有更多數據要發送,則需要檢查返回值並再次調用send()。您需要循環呼叫send(),直到完整發送完整的響應。

  • 「將緩衝區回送給發件人」對於HTTP服務器來說不是正確的做法。感覺就像你拿了一個ECHO服務器的例子,並且正在修改它的HTTP。 HTTP比ECHO實現起來要複雜得多。

隨着中說,嘗試更多的東西像這樣(未經測試,但應該給你什麼是參與一個想法):

#include <iostream> 
#include <string> 
#include <sstream> 
#include <vector> 
#include <map> 
#include <stdexcept> 
#include <algorithm> 

// Need to link with Ws2_32.lib 
#pragma comment (lib, "Ws2_32.lib") 
// #pragma comment (lib, "Mswsock.lib") 

#define DEFAULT_BUFLEN 512 
#define DEFAULT_PORT "8080" 

class WinsockError : public std::runtime_error 
{ 
public: 
    int ErrCode; 
    std::string FuncName; 

    WinsockError(const char *func) 
     : std::runtime_error("Winsock function failed"), ErrCode(WSAGetLastError()), FuncName(func) 
    { 
    } 

    WinsockError(int err, const char *func) 
     : std::runtime_error("Winsock function failed"), ErrCode(err), FuncName(func) 
    { 
    } 
}; 

class WinsockDisconnected : public std::runtime_error 
{ 
public: 
    bool WasGraceful; 

    WinsockDisconnected(bool graceful) 
     : std::runtime_error("socket disconnected"), WasGraceful(graceful) 
    { 
    } 
}; 

class JustStopNow : public std::runtime_error 
{ 
public: 
    JustStopNow() 
     : std::runtime_error("") 
    { 
    } 
}; 

class WSAInit 
{ 
private: 
    WSAInit(const WSAInit &) {} 
    WSAInit& operator=(const WSAInit &) { return *this; } 

public: 
    WSAInit() { 
     WSADATA wsaData; 
     int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
     if (iResult != 0) { 
      throw WinsockError(iResult, "WSAStartup"); 
     } 
    } 

    ~WSAInit() { 
     WSACleanup(); 
    } 
}; 

class Socket 
{ 
private: 
    SOCKET m_sock; 

    Socket(const Socket &) {} 
    Socket& operator=(const Socket &) { return *this; } 

public: 
    Socket(SOCKET s = INVALID_SOCKET) : m_sock(s) {} 

    ~Socket() { 
     Close(); 
    } 

    void Close() { 
     if (m_sock != INVALID_SOCKET) { 
      shutdown(m_sock, SD_BOTH); 
      closesocket(m_sock); 
      m_sock = INVALID_SOCKET; 
     } 
    } 

    operator SOCKET() { 
     return m_sock; 
    } 

    bool operator !() { 
     return (m_sock == INVALID_SOCKET); 
    } 

    Socket& operator =(SOCKET s) { 
     if (m_sock != s) { 
      close(); 
      m_sock = s; 
     } 
     return *this; 
    } 

    int ReadSome(void *buffer, int buflen) 
    { 
     int iResult = recv(m_sock, buffer, buflen, 0); 
     if (iResult == SOCKET_ERROR) { 
      iResult = WSAGetLastError(); 
      switch (iResult) { 
       case WSAECONNABORTED: 
       case WSAECONNRESET: 
       case WSAENETRESET: 
        throw WinsockDisconnected(false); 
      } 
      throw WinsockError(iResult, "recv"); 
     } 

     if (iResult == 0) { 
      throw WinsockDisconnected(true); 
     } 

     std::cout << "Bytes received: " << iResult << std:::endl; 
     std::cout.write((char*)recvbuf, iResult); 
     std::cout << std::endl; 

     return iResult; 
    } 

    void ReadAll(void *buffer, int buflen) 
    { 
     unsigned char *pbuffer = (unsigned char *) buffer; 
     int iResult; 

     while (buflen > 0) { 
      iResult = ReadSome(pbuffer, buflen); 
      pbuffer += iResult; 
      buflen -= iResult; 
     } 
    } 

    void Send(const std:string &s) 
    { 
     Send(s.c_str(), s.size()); 
    } 

    void Send(const void *buffer, int buflen) 
    { 
     const unsigned char *pbuffer = (const unsigned char *) buffer; 
     int iResult; 

     while (buflen > 0) { 
      iResult = send(m_sock, pbuffer, buflen, 0); 
      if (iResult == SOCKET_ERROR) { 
       iResult = WSAGetLastError(); 
       switch (iResult) { 
        case WSAECONNABORTED: 
        case WSAECONNRESET: 
        case WSAENETRESET: 
         throw WinsockDisconnected(false); 
       } 
       throw WinsockError(iResult, "send"); 
      } 

      std::cout << "Bytes send: " << iResult << std:::endl; 
      std::cout.write((char*)pbuffer, iResult); 
      std::cout << std::endl; 

      pbuffer += iResult; 
      buflen -= iResult; 
     } 
    } 
}; 

class AddrInfoPtr 
{ 
private: 
    struct addrinfo *m_info; 

    AddrInfoPtr(const AddrInfoPtr &) {} 
    AddrInfoPtr& operator=(const AddrInfoPtr &) { return *this; } 

public: 
    AddrInfoPtr(struct addrinfo *info = NULL) : m_info(info) {} 

    ~AddrInfoPtr() { 
     if (m_info) { 
      freeaddrinfo(m_info); 
     } 
    } 

    operator struct addrinfo*() { 
     return m_info; 
    } 

    struct addrinfo* operator ->() { 
     return m_info; 
    } 

    bool operator !() { 
     return (m_info == NULL); 
    } 

    struct addrinfo** operator & { 
     return &m_info; 
    } 
}; 

char UpperCaseChar(char ch) 
{ 
    return std::toupper(ch); 
} 

void UpperCaseStr(std::string &s) 
{ 
    std::transform(s.begin(), s.end(), s.begin(), UpperCaseChar); 
} 

void LTrimLWS(std::string &s) 
{ 
    s.erase(0, s.find_first_not_of(" \t")); 
} 

void RTrimLWS(std::string &s) 
{ 
    s.erase(s.find_last_not_of(" \t")+1); 
} 

void TrimLWS(std::string &s) 
{ 
    LTrimLWS(s); 
    RTrimLWS(s); 
} 

typedef std::map<std::string, std::string> NameValueMap; 
typedef std::vector<unsigned char> ByteVec; 

class InputBuffer 
{ 
private: 
    Socket &m_sock; 
    ByteVec m_buf; 

    static void ParseHeader(const std::string &header, NameValueMap &headers) 
    { 
     if (header.empty()) { 
      return; 
     } 

     std::string name, value; 
     std::istringstream iss(header); 

     std::getline(iss, name, ':'); 
     TrimLWS(name); 

     std::getline(iss, value); 
     TrimLWS(value); 

     UpperCaseStr(name); 

     NameValueMap::iterator iter = headers.find(name); 
     if (iter != headers.end()) 
      iter->second += ("," + value); 
     else 
      headers.insert(std::make_pair(name, value)); 
    } 

public: 
    InputBuffer(Socket &s) : m_sock(s) {} 

    bool HasPendingData() 
    { 
     return !m_buf.empty(); 
    } 

    bool FillFromSocket(int Timeout = -1) 
    { 
     if (Timeout >= 0) { 
      fd_set rfd; 
      FD_ZERO(&rfd); 
      FD_SET(m_sock, &rfd); 

      timeval t; 
      t.tv_sec = Timeout/1000; 
      t.tv_usec = (Timeout % 1000) * 1000; 

      switch (select(0, &rfd, NULL, NULL, &t)) { 
       case SOCKET_ERROR: 
        throw WinsockError("select"); 
       case 0: 
        return false; 
      } 
     } 

     unsigned char buf[DEFAULT_BUFLEN]; 

     int iResult = m_sock.ReadSome(buf, sizeof buf); 
     m_buf.insert(m_buf.end(), &buf[0], &buf[iResult]); 

     return true; 
    } 

    std::string ReadLine() 
    { 
     ByteVec::iterator iter = std::find(m_buf.begin(), m_buf.end(), '\n'); 
     while (iter == m_buf.end()) { 
      ByteVec::size_type offset = m_buf.size(); 
      FillFromSocket(); 
      iter = std::find(m_buf.begin()+offset, m_buf.end(), '\n'); 
     } 

     std::string::size_type len = std::distance(m_buf.begin(), iter); 
     if ((len > 0) && (*(iter-1) == '\r')) { 
      --len; 
     } 

     std::string out(m_buf.begin(), m_buf.begin()+len); 
     m_buf.erase(m_buf.begin(), iter+1); 

     return out; 
    } 

    void ReadHeaders(NameValueMap &headers) 
    { 
     std::string line; 
     std::ostringstream oss; 

     do { 
      line = ReadLine(); 
      if (line.empty()) { 
       break; 
      } 

      if ((line[0] == ' ') || (line[0] == '\t')) { 
       LTrimLWS(line); 
       oss << ' ' << line; 
      } 
      else { 
       ParseHeader(oss.str(), headers); 
       RTrimLWS(line); 
       oss.str(line); 
      } 
     } 
     while (true); 

     ParseHeader(oss.str(), headers); 
    } 

    void Read(void *buffer, int buflen) 
    { 
     unsigned char *pbuffer = (unsigned char *) buffer; 

     while (buflen > 0) { 
      if (m_buf.empty()) { 
       FillFromSocket(); 
      } 

      ByteVec::size_type len = std::max(m_buf.size(), buflen); 
      ByteVec::iterator start = m_buf.begin(); 
      ByteVec::iterator finish = start+len; 

      std::copy(start, finish, pbuffer); 
      m_buf.erase(start, finish); 

      pbuffer += len; 
      buflen -= len; 
     } 
    } 
}; 

int __cdecl main(void) 
{ 
    try { 
     // Initialize Winsock 
     TWSAInit wsa; 

     // Resolve the server address and port 

     Socket ListenSocket; 

     { 
     struct addrinfo hints; 
     AddrInfoPtr result; 

     ZeroMemory(&hints, sizeof(hints)); 
     hints.ai_family = AF_INET; 
     hints.ai_socktype = SOCK_STREAM; 
     hints.ai_protocol = IPPROTO_TCP; 
     hints.ai_flags = AI_PASSIVE; 

     iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
     if (iResult != 0) { 
      throw WinsockError(iResult, "getaddrinfo"); 
     } 

     // Create a TCP listening socket 

     ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
     if (!ListenSocket) { 
      throw WinsockError("socket"); 
     } 

     // Setup the TCP listening socket 

     iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
     if (iResult == SOCKET_ERROR) { 
      throw WinsockError("bind"); 
     } 

     } 

     iResult = listen(ListenSocket, SOMAXCONN); 
     if (iResult == SOCKET_ERROR) { 
      throw WinsockError("listen"); 

     std::cout << "Listening" << std::endl; 

     do { 
      // Accept a client socket 

      Socket ClientSocket = accept(ListenSocket, NULL, NULL); 
      if (!ClientSocket) { 
       throw WinsockError("accept"); 
      } 

      std::cout << "Client connected" << std::endl; 

      // TODO: move the following to a thread so you can 
      // service multiple clients at the same time... 

      try { 
       // read HTTP requests until disconnect 

       InputBuffer io(ClientSocket); 
       bool keepAlive; 

       do { 
        std::string line, value; 
        std::string method, resource; 
        int majorVersion, minorVersion; 
        NameValueMap headers; 
        ByteVec body; 
        std::ostringstream response; 

        line = io.ReadLine(); 

        // parse request line 

        { 
        std::istringstream iss(line); 
        std::getline(iss, method, ' '); 
        UpperCaseStr(method); 
        std::getline(iss, resource, ' '); 
        std::getline(iss, value); 
        } 

        { 
        std::istringstream iss(value); 
        std::getline(iss, value, '/'); 
        char dot; 

        if ((value != "HTTP") || 
         !(iss >> majorVersion >> dot >> minorVersion) || 
         (dot != '.')) { 
         response << "HTTP/1.1 400 Bad Request\r\n" 
           << "Connection: close\r\n" 
           << "Content-Length: 0\r\n" 
           << "\r\n"; 
         ClientSocket.Send(response.str()); 
         throw JustStopNow(); 
        } 
        } 

        // read request headers 

        io.ReadHeaders(headers); 

        // HTTP 1.1+ requires a "Host" header 

        if (
         (majorVersion > 1) || 
         ((majorVersion == 1) && (minorVersion >= 1)) 
         ) { 
         if (headers["HOST"].empty()) { 
          response << "HTTP/1.1 400 Bad Request\r\n" 
            << "Connection: close\r\n" 
            << "Content-Length: 0\r\n" 
            << "\r\n"; 
          ClientSocket.Send(response.str()); 
          throw JustStopNow(); 
         } 
        } 

        // check if client wants a 100 response before it sends the request body 

        value = headers["EXPECT"]; 
        UpperCaseStr(value); 

        if (value.find("100-CONTINUE") != std::string::npos) { 
         if (!io.HasPendingData()) { 
          if (!io.FillFromSocket(0)) { 
           ClientSocket.Send("HTTP/1.1 100 Continue\r\n"); 
          } 
         } 
        } 

        // determine if any body is being sent, and if so then read it 

        value = headers["TRANSFER-ENCODING"]; 
        UpperCaseStr(value); 

        if ((!value.empty()) && (value != "IDENTITY")) { 
         do { 
          line = io.ReadLine(); 

          std::istringstream iss(line); 
          ByteVec::size_type size = 0; 
          if (!(iss >> std::hex >> size)) { 
           response << "HTTP/1.1 400 Bad Request\r\n" 
             << "Connection: close\r\n" 
             << "Content-Length: 0\r\n" 
             << "\r\n"; 
           ClientSocket.Send(response.str()); 
           throw JustStopNow(); 
          } 

          if (size > 0) { 
           ByteVec::size_type offset = body.size(); 
           body.resize(offset+size); 
           io.Read(&body[offset], size); 
           io.ReadLine(); 
          } 
          else if (size == 0) { 
           break; 
          } 
          else { 
           response << "HTTP/1.1 400 Bad Request\r\n" 
             << "Connection: close\r\n" 
             << "Content-Length: 0\r\n" 
             << "\r\n"; 
           ClientSocket.Send(response.str()); 
           throw JustStopNow(); 
          } 
         } 
         while (true); 

         io.ReadHeaders(headers); 
        } 
        else { 
         value = headers["CONTENT-LENGTH"]; 
         if (!value.empty()) { 
          std::istringstream iss(value); 
          ByteVec::size_type size = 0; 
          if (!(iss >> size)) { 
           response << "HTTP/1.1 400 Bad Request\r\n" 
             << "Connection: close\r\n" 
             << "Content-Length: 0\r\n" 
             << "\r\n"; 
           ClientSocket.Send(response.str()); 
           throw JustStopNow(); 
          } 

          if (size > 0) { 
           body.resize(size); 
           io.Read(&body[0], size); 
          } 
          else if (size != 0) { 
           response << "HTTP/1.1 400 Bad Request\r\n" 
             << "Connection: close\r\n" 
             << "Content-Length: 0\r\n" 
             << "\r\n"; 
           ClientSocket.Send(response.str()); 
           throw JustStopNow(); 
          } 
         } 
         else if ((method == "POST") || (method == "PUT")) { 
          response << "HTTP/1.1 411 Length Required\r\n" 
            << "Connection: close\r\n" 
            << "Content-Length: 0\r\n" 
            << "\r\n"; 
          ClientSocket.Send(response.str()); 
          throw JustStopNow(); 
         } 
        } 

        // determine if a keep-alive is requested 

        value = headers["CONNECTION"]; 
        UpperCaseStr(value); 

        keepAlive = (
         (majorVersion > 1) || 
         ((majorVersion == 1) && (minorVersion >= 1)) 
         ) 
         ? (value != "CLOSE") 
         : (value == "KEEP-ALIVE"); 

        // process method, resource, headers, and body as needed 

        response << "HTTP/1.1 200 OK\r\n"; 
          << "Connection: " << (keepAlive ? "keep-alive" : "close") << "\r\n" 
          << "Content-Type: text/plain\r\n" 
          << "Content-Length: 4\r\n" 
          << "\r\n" 
          << "Ahoj"; 
        ClientSocket.Send(response.str()); 
       } 
       while (keepAlive); 
      } 
      catch (const JustStopNow &) { 
      } 
      catch (const WinsockDisconnected &e) { 
       std::cout << "Client disconnected " << e.WasGraceful ? "gracefully" : "abnormally" << std::endl; 
      } 
      catch (const WinsockError &e) { 
       std::cerr << "Client disconnected because " << e.FuncName << " failed with error: " << e.ErrCode << std::endl; 
      } 
     } 
     while (true); 
    } 
    catch (const WinsockError &e) { 
     std::cerr << e.FuncName << " failed with error: " << e.ErrCode << std::endl; 
     return 1; 
    } 

    return 0; 
} 
+0

我意識到我不解析客戶端請求,但那是故意的。我最初的目標是發送迴應,然後在請求後發揮作用。但是你的回答很好,謝謝。 – Darlyn