使用curllib将数据发送到服务器

时间:2014-04-23 16:06:35

标签: sockets http curl tcp client

我对所有这些http事情都很陌生,我正在尝试与服务器进行通信。

我需要编写发布到服务器的客户端 - 我知道服务器返回了什么,但我不知道如何将数据发送给它:

  1. 我(客户端)使用HTTP将XML(二进制格式)发布到服务器url:192.168.2.111/senddata(即post / senddata)。

  2. 服务器响应是:

    TCP: [ACK] Seq=1274 Ack=504 Win=525088 Len=0
    

    I.E这是问题 - 服务器不回复HTTP回复。 协议服务器在我发送之后使用XML是TCP,这使得curl_easy_perform 不回来。

  3. 在步骤2中的服务器TCP回复之后,我 - 客户端应该使用HTTP Continuation或非HTTP流量将循环中的二进制数据发送到服务器。

  4. 服务器异步性回答

    TCP: [ACK] Seq=1274 Ack=3424 Win=522176 Len=0
    

    发送每个二进制数据。

  5. 因此,要在步骤1中发送XML,我使用

    curl_easy_setopt(mCurlHndl, CURLOPT_URL, "192.168.2.111");
    curl_easy_setopt(mCurlHndl, CURLOPT_CUSTOMREQUEST, "POST /senddata");
    curl_easy_setopt(mCurlHndl, CURLOPT_POST, 1L);
    curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDS, sXML.c_str());
    curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDSIZE, sXML.length());
    
    headers = curl_slist_append(headers, "Content-Type: application/octet-stream");
    headers = curl_slist_append(headers, "Accept:");
    headers = curl_slist_append(headers, (string("Content-Length: ") + string(to_string(sXML.length()))).c_str());
    curl_easy_setopt(mCurlHndl, CURLOPT_HTTPHEADER, headers);
    
    res = curl_easy_perform(mCurlHndl);
    

    服务器确实发送回复:

    TCP: [ACK] Seq=1274 Ack=504 Win=525088 Len=0
    

    (当然还有其他seq / ack / win号码)。

    好的,这里开始出现问题。

    一个。 curl_easy_perform没有返回,因为(我认为)服务器回复不是HTTP,而是TCP。

    湾好吧,让我说我可以绕过它给予超时

        curl_easy_setopt(mCurlHndl, CURLOPT_TIMEOUT_MS, 1000);
    

    但我知道我做错了什么。

    ℃。假设我给出了超时,现在在步骤3中我需要使用HTTP Continuation或非HTTP流量发送循环数据流。

    我不知道该怎么做,因为它不应该像第1步那样经常发布。 它应该是HTTP Continuation或非HTTP流量。

    对不起我的错误解释,但这再次来自我对HTTP的非常小的经验。

    似乎在第1步之后,服务器中断正常的http连接规则以及我需要发送它的是循环中的二进制数据但是又一次,我不知道如何执行第2步和第3步.IE如何获取来自服务器的TCP ACK使用curllib,我将知道转到第3步,以及如何(步骤3)通过相同的连接(我认为)循环中的二进制数据发送到服务器。

    我想补充说服务器返回应该返回的内容。在步骤2中服务器应该返回TCP:[ACK] Seq = 1274 Ack = 504 Win = 525088 Len = 0,因为这是服务器应该做的 - 这是服务器协议。这不是我没有正确发送(在步骤1中),这就是它发送TCP回复而不是http的原因。

    这是Wireshark日志: 192.168.2.7是客户端(有效)。 192.168.2.111是服务器。 在第一行(seq 9)中,clinet发布二进制xml(POST / senddata),然后开始循环二进制数据流发送,如您所见:

    9   0.173574000 192.168.2.7     192.168.2.111   HTTP    380     POST /senddata HTTP/1.1  (application/octet-stream)
    10  0.176611000 192.168.2.111   192.168.2.7     TCP     60      4089 > 53419 [ACK] Seq=1274 Ack=504 Win=525088 Len=0
    11  0.182581000 192.168.2.111   192.168.2.7     UDP     90      Source port: 4020  Destination port: 4005
    12  0.553367000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    13  0.553403000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    14  0.555539000 192.168.2.111   192.168.2.7     TCP     60      4089 > 53419 [ACK] Seq=1274 Ack=3424 Win=522176 Len=0
    15  0.555698000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    16  0.555724000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    17  0.555724000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    18  0.555724000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    19  0.558870000 192.168.2.111   192.168.2.7     TCP     60      4089 > 53419 [ACK] Seq=1274 Ack=6344 Win=519248 Len=0
    20  0.559033000 192.168.2.7     192.168.2.111   HTTP    1354    Continuation or non-HTTP traffic
    
    ..... and many other sends like seq 12 - seq 20 ........
    

    我如何用curllib做这样的事情 - 这是我的问题。

    再次感谢

1 个答案:

答案 0 :(得分:0)

您没有正确使用curl发送HTTP POST请求。试试这个:

curl_easy_setopt(mCurlHndl, CURLOPT_URL, "http://192.168.2.111/senddata");
curl_easy_setopt(mCurlHndl, CURLOPT_POST, 1L);
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDS, sXML.c_str());
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDSIZE, sXML.length());

struct curl_slist *headers = curl_slist_append(NULL, "Content-Type: application/octet-stream");
headers = curl_slist_append(headers, "Accept:");
curl_easy_setopt(mCurlHndl, CURLOPT_HTTPHEADER, headers);

res = curl_easy_perform(mCurlHndl);
curl_slist_free_all(headers);

// process reply using curl_easy_getinfo() and curl_easy_recv() as needed...

话虽如此,您确定要将Content-Type作为application/octet-stream发送吗?通常,XML使用text/xmlapplication/xml或其他与XML相关的Content-Type发布,因此服务器知道它正在处理XML数据。 application/octet-stream指的是当其实际类型未知时的任意二进制数据。

此外,将Accept标题设置为空值基本上意味着您不接受任何回复数据。除非您只想接受特定的Content-Type回复类型,或者想要接受服务器要发送的任何数据,否则您应该省略Accept标题。

阅读RFC 2616以获取HTTTP协议的正式定义及其工作原理。

更新:由于您显然在处理自定义协议而非标准HTTP,因此无法使用curl_easy_perform()发送HTTP请求。您必须启用CURLOPT_CONNECT_ONLY选项,以便curl_easy_perform()只打开套接字连接,然后使用curl_easy_send()发送实际请求和后续二进制数据,例如:

CURLcode curl_send(CURL *curl, const void * buffer, size_t buflen)
{
    size_t sent;

    uint8_t *pbuf = (uint8_t*) buffer;
    while (buflen > 0)
    {
        do
        {
            res = curl_easy_send(curl, pbuf, buflen, &sent); 
        }
        while (res == CURLE_AGAIN);

        if (res != CURLE_OK)
            return res;

        pbuf += sent;
        buflen -= sent;
    }
    while (buflen > 0);

    return CURLE_OK;
} 

mCurlHndl = curl_easy_init();

...

curl_easy_setopt(mCurlHndl, CURLOPT_URL, "http://192.168.2.111");
curl_easy_setopt(mCurlHndl, CURLOPT_CONNECT_ONLY, 1);

res = curl_easy_perform(mCurlHndl);
if (res == CURLE_OK)
{
    string req =
        "POST /senddata HTTP/1.1\r\n"
        "Content-Type: application/octet-stream\r\n"
        "Content-Length: " + to_string(sXML.length()) + "\r\n"
        "\r\n"
        + sXML;

    res = curl_send(mCurlHndl, req.c_str(), req.length());
    if (res !- CURLE_OK) ...

    res = curl_send(mCurlHndl, ...binary data...);
    if (res !- CURLE_OK) ...

    res = curl_send(mCurlHndl, ...binary data...);
    if (res !- CURLE_OK) ...

    res = curl_send(mCurlHndl, ...binary data...);
    if (res !- CURLE_OK) ...
    ...
}

...

curl_easy_cleanup(mCurlHndl);