当前位置: 首页 > 知识库问答 >
问题:

HTTP 1.0 保持活动状态服务器和 curl

东方和惬
2023-03-14

我正忙着在嵌入式平台上实现自己的超文本传输协议服务器。从技术上讲,服务器符合HTTP 1.0,因此它希望客户端发送标头“连接:保持活着”以保持连接打开。

实现如下所示。我删除了解析HTTP头并执行请求的代码,以使帖子尽可能简短:

int Service_Request(int conn) {

    struct ReqInfo reqinfo;
    volatile int resource = 0;
    int retval = 0;
    Req_Result req_result = GOT_REQ;
    
    InitReqInfo(&reqinfo);

    /* while we still have HTTP requests to process */
    while (req_result == GOT_REQ)
    {
        
        /*  Get HTTP request, there are 3 different return values:
         * GOT_REQ: we got a valid HTTP request
         * TIMEOUT_REQ we timed out waiting for a request
         * ERROR_REQ there was some error receiving from the socket
         * usually because the connection was closed by the peer*/
        req_result = Get_Request(conn, &reqinfo);
        if ( req_result == TIMEOUT_REQ)
        {
            /* timed out waiting for the client, exit */
            retval = 0;
            break;
        }
        else if (req_result == ERROR_REQ)
        {
            /* some error, exit */
            retval = -1;
            break;
        }
        /* Process the request GET, PUT and POST is supported*/
        if (reqinfo.method == GET) 
        {
            /* code to handle GET*/
        } 
        /* PUT and POST are handled in the same way */
        else if ((reqinfo.method == PUT) || (reqinfo.method == POST) )
        {
            /* Code to handle PUT and POST*/        
        } 
        else 
        {
            /* not supported, code should never get here */
            reqinfo.status = 501;
            Return_Error_Msg(conn, &reqinfo);
        }
        /*Diag_Msg("Client Request: \r\n");
        Diag_Msg(reqinfo.clientRequest);*/
        
        /*
         * the reqinfo.keep_alive flag will be set to 1 if the 
         * "Connection: Keep-Alive" header was sent by the client
         */
        if(reqinfo.keep_alive == 0)
        {
            break;
        }

        reqinfo.keep_alive_max--;
        if(reqinfo.keep_alive_max <= 0 )
        {
            /*
             * the connection has been reused for the maxmum amount of times, stop
             */
            break;
        }
        /*
         * If we get here, we will clear the memory used for the client request
         * and go to the beginning of the while loop to receive another request
         */
        Writeline(conn,"\r\n",2);
        FreeReqInfo(&reqinfo);
        
    }
    FreeReqInfo(&reqinfo);
    return (retval);
}

Get_Request函数如下所示:

Req_Result Get_Request(int conn, struct ReqInfo * reqinfo) {

    char   buffer[MAX_REQ_LINE] = {0};
    int    rval;
    fd_set fds;
    struct timeval tv;


    /*  Set timeout to 5 seconds if this is the first request since the client connected, wait 5 seconds
     * Otherwise, wait 5ms */
    if(reqinfo->first_request == 1)
    {
        tv.tv_sec  = 5;
        tv.tv_usec = 0;
        reqinfo->first_request = 0;
    }
    else
    {
        tv.tv_sec  = reqinfo->keep_alive_timeout;
        tv.tv_usec = 0;
    }

    /*  Loop through request headers. If we have a simple request,
    then we will loop only once. Otherwise, we will loop until
    we receive a blank line which signifies the end of the headers,
    or until select() times out, whichever is sooner.                */
    do {

    /*  Reset file descriptor set  */

    FD_ZERO(&fds);
    FD_SET (conn, &fds);


    /*  Wait until the timeout to see if input is ready  */

    rval = select(conn + 1, &fds, NULL, NULL, &tv);


    /*  Take appropriate action based on return from select()  */

    if ( rval < 0 ) 
    {
        Diag_Msg("Error calling select() in get_request()");
        return (ERROR_REQ);
    }
    else if ( rval == 0 ) {

        /*  input not ready after timeout  */

        return (TIMEOUT_REQ);

    }
    else {

        /*  We have an input line waiting, so retrieve it  */
        memset(buffer,0,MAX_REQ_LINE - 1);
        if(Readline(conn, buffer, MAX_REQ_LINE - 1) == -1)
        {
            return (ERROR_REQ);
        }
        if(reqinfo->clientRequest == NULL)
        { 
            reqinfo->clientRequest = calloc(MAX_REQ_LINE - 1, sizeof(char));
            strncpy(reqinfo->clientRequest,buffer,MAX_REQ_LINE - 1);
        }
        else
        {
            strncat(reqinfo->clientRequest,buffer,MAX_REQ_LINE - 1);
        }
        Trim(buffer);

        if ( buffer[0] == '\0' )
        break;

        if ( Parse_HTTP_Header(buffer, reqinfo) )
        break;
    }
    } while ( reqinfo->type != SIMPLE );

    return (GOT_REQ);
}

用英语描述这个服务器的工作方式:服务器接收第一个请求。它解析报头,如果发现“连接:保持活动”报头,它设置一个标志。服务器继续处理这个请求。完成后,它会检查保活标志。如果清除该选项,服务器将关闭连接。如果设置,服务器将执行清理操作,并继续等待同一连接上的另一个请求。诸如此类。

我用卷曲测试了这个:

C:\curl>curl -v -H "Connection: Keep-Alive" --data-binary @vid1.bin 10.84.67.129/s1p0:1/vid[1-2].bin

[1/2]: 10.84.67.129/s1p0:1/vid1.bin --> <stdout>
--_curl_--10.84.67.129/s1p0:1/vid1.bin
* About to connect() to 10.84.67.129 port 80 (#0)
*   Trying 10.84.67.129...
* connected
* Connected to 10.84.67.129 (10.84.67.129) port 80 (#0)
> POST /s1p0:1/vid1.bin HTTP/1.1
> User-Agent: curl/7.28.1
> Host: 10.84.67.129
> Accept: */*
> Connection: Keep-Alive
> Content-Length: 51200
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
* HTTP 1.0, assume close after body
< HTTP/1.0 100 Continue
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: DTSVU v0.1
< Content-Type: text/html
* HTTP/1.0 connection set to keep alive!
< Connection: Keep-Alive
< Keep-Alive: timeout=5, max=10
<
* Connection #0 to host 10.84.67.129 left intact

[2/2]: 10.84.67.129/s1p0:1/vid2.bin --> <stdout>
--_curl_--10.84.67.129/s1p0:1/vid2.bin
* Connection #0 seems to be dead!
* Closing connection #0
* About to connect() to 10.84.67.129 port 80 (#0)
*   Trying 10.84.67.129...
* connected
* Connected to 10.84.67.129 (10.84.67.129) port 80 (#0)
> POST /s1p0:1/vid2.bin HTTP/1.1
> User-Agent: curl/7.28.1
> Host: 10.84.67.129
> Accept: */*
> Connection: Keep-Alive
> Content-Length: 51200
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
* HTTP 1.0, assume close after body
< HTTP/1.0 100 Continue
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: DTSVU v0.1
< Content-Type: text/html
* HTTP/1.0 connection set to keep alive!
< Connection: Keep-Alive
< Keep-Alive: timeout=5, max=10
<
* Connection #0 to host 10.84.67.129 left intact
* Closing connection #0

如您所见,curl说:连接#0似乎已死!在第一个请求完成后。然后它继续关闭连接并打开一个新连接。我确信我正确地实现了HTTP 1.0保持活动功能。所以我的问题是:在第一个请求完成后,curl对连接有什么期望?为什么它决定连接已死?

PS以上代码改编自http://www.paulgriffiths.net/program/c/webserv.php

共有1个答案

奚高扬
2023-03-14

我解决了。如果服务器回复HTTP/1.1和“Content-Length: 0”,curl就重用这个连接。我的服务器回复看起来像这样

< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: DTSVU v0.1
< Content-Type: text/html
< Connection: Keep-Alive
< Keep-Alive: timeout=1, max=95
< Content-Length: 0

在连接的第五次重复使用之后。

 类似资料:
  • 问题内容: 我在当前的项目中使用它来处理客户端身份验证等。当前它仅打印出客户端地址/端口,以便我可以检查一个TCP连接是否用于多个请求()或是否有新连接为每个请求建立(因此每次都会进行新的SSL握手)。当我使用FireFox对服务器发出多个请求时,我可以看到keep- alive正在运行。因此服务器部分可以很好地处理GET和POST请求。 如果我过去对服务器发出请求(在这种情况下, 不 使用SSL

  • 我正在创建一个客户端服务器应用程序。服务器已经设计好,等待从客户端连接。现在在客户机部分中,我希望在应用程序的整个生命周期中保持连接活动,并且只有当主客户机应用程序关闭或关闭或者服务器关闭它时,连接才会关闭。 在处理程序中我有:

  • 问题内容: 我正在使用POST方法。我需要创建一次,并且应该使用Keep Alive Connection。但是我认为,它每次都会建立一个新的连接。 因此,我需要使用 保持活动 连接。 这是我的代码段,很多帮助将不胜感激。 而且logcat日志是: 问题答案: 10:07:29.746:D / org.apache.http.headers(1529):>>连接:保持活动 您正在要求保持活动状态。

  • 问题内容: 我用来登录远程服务器。 问题 : 当我在工作场所时,它始终保持连接并且可以正常工作。不幸的是,在我在家中与远程服务器连接后,终端会在10到15分钟内死机。 控制台上没有错误/超时报告,但是光标不能再移动了。 输入检查登录用户时,那里有一些僵尸登录用户,我必须手动将其杀死。 这很烦人。谁能帮我? 问题答案: 在客户端运行的ssh守护程序(sshd),如果客户端变为静默(即,不发送信息),

  • 问题内容: 我正在尝试连接到API,对用户进行身份验证,然后查看用户详细信息。这是通过首先访问登录端点来完成的 登录,然后单击以下内容查看用户详细信息: 所有这些都可以在Web浏览器中使用。但是,一旦我尝试使用Curl,登录就可以正常工作,但是在尝试查看用户详细信息时,我又得到了401未经授权的错误。我相信这是因为Curl没有正确保存会话cookie?有人可以指出为什么它不起作用以及如何解决吗?我

  • 当我录制这个命令以显示mongodb的状态时