代码之家  ›  专栏  ›  技术社区  ›  user3700538

C中的HTTP GET服务器,长等待(TTFB)

  •  1
  • user3700538  · 技术社区  · 8 年前

    不幸的是,在收到浏览器头和收到空缓冲区之间有几秒钟的间隔 recv 现在我可以发送一个响应。

    socklen_t clientAddressLength;
    int clientSocket = accept(socket, (struct sockaddr *)&socketAddress, &clientAddressLength);
    if (clientSocket < 0) {ESP_LOGI(TAG, "failed 3!"); goto network_task_finish;}
    
    if (setsockopt(clientSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
       ESP_LOGI(TAG, "Cannot Set SO_SNDTIMEO for socket");
    if (setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
       ESP_LOGI(TAG, "Cannot Set SO_RCVTIMEO for socket");
    while (1) {
       ret = recv(clientSocket, recv_buf, NETWORK_RECV_BUF_LEN - 1, 0);
       if (ret <= 0) break;
       if (ret <= 2 && *recv_buf == '\r') break;
       if (ret < NETWORK_RECV_BUF_LEN)
          recv_buf[ret] = '\0';
       ESP_LOGI(TAG, "RECV");
       if (strstr(recv_buf," HTTP/")) {
          char *ptr = recv_buf;
          if (strncmp(recv_buf, "GET ", 4) == 0)
             ptr += 4;
          else if (strncmp(recv_buf, "POST ", 4) == 0)
             ptr += 5;
          else
             continue;
          ESP_LOGI(TAG, "HEADER!");
       }
    }
    
    ESP_LOGI(TAG, "RESPONSE");
    send(clientSocket, "HTTP/1.1 200 OK\r\n", 17, 0);
    send(clientSocket, "Content-Type: text/html\r\n", 25, 0);
    send(clientSocket, "Connection: close\r\n", 19, 0);
    send(clientSocket, "\r\n", 2, 0);
    send(clientSocket, "WORKS", 5, 0);
    ESP_LOGI(TAG, "SEND");
    

    日志:

    server: RECV
    server: HEADER!
    ... long time ...
    server: RESPONSE
    server: SEND
    

    处理请求的准确方式是什么? 也许我不必等待它的结束,或者我可以用另一种方式检测标题的结束

    1 回复  |  直到 8 年前
        1
  •  3
  •   Some programmer dude    8 年前

    问题似乎不是你不知道请求如何结束(只有一个空行),而是你如何结束 检查 为了它。

    您必须记住,HTTP是建立在TCP之上的,而TCP是 流动 没有消息边界或固定大小数据包的协议。

    这意味着您可以在一次操作中获得整个请求 recv 打电话,或两个,或三个或更多。并且只有在单个 recv 给你的电话 只是 空行,没有其他,这是一个非常不可能的事件。这也可能给你一个 假的 请求结束,因为换行符可能位于标头的中间。

    相反,我建议您重新设计呼叫的接收代码 recv 并附加到缓冲区。然后在循环中,检查 字节是双换行序列( \r\n\r\n ). 如果是, 然后 您已经找到了请求的结尾,可以中断循环,继续处理请求,并实际检查所需内容( GET POST 等等)。