【问题标题】:Bug keep-alive delay错误保持活动延迟
【发布时间】:2017-08-21 03:17:02
【问题描述】:

此代码使用 keep-alive 连接以加载许多共享相同 IP 地址的域,但在前 25 个域之后有一个错误,即每次域加载延迟 30 秒!如何解决?

#pragma comment(lib,"ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
int main(){
    WSAData wsaData;
    WORD DllVersion = MAKEWORD(2, 1);
    if (WSAStartup(DllVersion, &wsaData) != 0) {
        MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
        exit(1);
    }
    SOCKADDR_IN addr;
    int sizeofaddr = sizeof(addr);
    addr.sin_addr.s_addr = inet_addr("123.123.123.123");
    addr.sin_port = htons(80);
    addr.sin_family = AF_INET;
    SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL);
    if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0)
    {
        MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
        return 0;
    }
    std::cout << "Connected!" << std::endl;
    char MTD[] = "GET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost:site.com\r\nConnection:close\r\n\r\n";
    send(Connection, MTD, sizeof(MTD), NULL);
    char MOTD[1];
    int result;
    while ((result = recv(Connection, MOTD, 1, NULL)) > 0){
        std::cout << MOTD[0]; // ...
    }
    if (result == 0) {
        // end of stream
        std::cout << "end of stream";
        close(Connection);
    } else if (result < 0) {
        // error
        std::cout << "error";
        perror("recv"); // at least
        close(Connection);
    } else {
        std::cout << "data received";
        // data received, in MOTD[0..result-1]
    }
};

【问题讨论】:

  • 您的代码中有一个更大的错误:您有一个大小为零的数组,并要求recv 向其中写入一个字节,从而溢出并具有未定义的行为 .
  • 接收数据的循环中还有一个错误,即您没有检查失败。请记住,recv 在连接关闭时返回0,但在出现错误时返回SOCKET_ERROR(通常为-1)。在 C++ 中,所有非零值都被认为是“真”,因此即使您遇到不可恢复的故障,您仍然会继续进行,就好像什么都没发生一样。而且一次读取一个字节的循环确实是无效的。
  • HTTP 中的行终止符定义为\r\n,而不是\n
  • @Someprogrammerdude:所有基于 BSD/POSIX 的套接字 API 实现,包括 WinSock,在套接字函数错误时返回 -1。 Windows 恰好有一个额外的 SOCKET_ERROR 常量,该常量定义为 -1 以提高代码可读性。

标签: c++ sockets keep-alive


【解决方案1】:
result=recv(Connection, MOTD, 1, NULL);
while(recv(Connection, MOTD, 1, NULL)){

这毫无意义。第一个recv() 将至少一个字节读入缓冲区或将result 设置为零或-1,然后您立即忽略它所做的任何事情并发出另一个recv(),您忽略其结果。它应该更像这样:

while ((result = recv(Connection, MOTD, 1, NULL)) > 0){
    // data received, in MOTD[0..result-1]
}
if (result == 0) {
    // end of stream
    close(Connection);
} else if (result < 0) {
    // error
    perror("recv"); // at least
    close(Connection);
}

NB 您根本没有使用 HTTP keepalive。您正在为每个请求创建一个新套接字并且永远不会关闭它,至少在您使用此答案中的代码之前。您通过Connection: keepalive 标头告诉服务器保持该连接处于活动状态,这只会浪费服务器资源。正确使用 HTTP keep-alive 或在每次请求后关闭套接字。

【讨论】:

  • EJP 完成,recv 返回是流的结尾,这意味着它没有错误地结束。在 25 个域之后,每个域加载 30 秒的延迟仍然是一个问题。
  • 现在正在关闭套接字,因为我正在使用此代码。以为我在加载一个 keep-alive 套接字,我该如何正确使用它?
  • “正确使用 HTTP keep-alive 或在每次请求后关闭套接字”的哪一部分您不明白?
  • 我的代码应该做些什么改变才能正确使用“HTTP keep-alive”?
  • @JavaOdd 太宽泛了。首先,重新使用连接而不是关闭它。请参阅 RFC。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多