sockets - 使用 curllib 向服务器发送数据

标签 sockets http curl tcp client

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

我需要编写发送到服务器的客户端 - 我知道服务器返回什么但我不确定如何向它发送数据:

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

  2. 服务器响应是:

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

    I.E 是问题所在 - 服务器不使用 HTTP 回复进行回复。 协议(protocol)服务器在我发送 XML 后使用 TCP,这使得 curl_easy_perform 不返回。

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

  4. 服务器异步响应

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

    对于每一个二进制数据发送。

所以要在步骤 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 号码)。

OK,问题开始了。

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

好的,假设我可以绕过它给超时

    curl_easy_setopt(mCurlHndl, CURLOPT_TIMEOUT_MS, 1000);

但我只知道我做错了什么。

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

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

对于我的错误解释,我深表歉意,但这再次来 self 对 HTTP 的极少经验。

似乎在第 1 步之后,服务器打破了正常的 http 连接规则,我需要发送它的是循环中的二进制数据,但同样,我不知道如何执行第 2 步和第 3 步。即如何获得来自服务器的 TCP ACK 使用 curllib 我将知道移动到第 3 步以及如何(第 3 步)通过相同的连接(我认为)将循环中的二进制数据发送到服务器。

我想补充一点,服务器会返回应该返回的内容。在第 2 步中,服务器应该返回 TCP:[ACK] Seq=1274 Ack=504 Win=525088 Len=0 因为这是服务器应该做的——这就是服务器协议(protocol)。这并不是我发送不正确(在第 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 做这样的事情 - 这是我的问题。

再次感谢

最佳答案

您没有正确使用 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 header 设置为空值基本上意味着您不接受任何回复数据。除非您只想接受特定的 Content-Type 回复类型,或者想接受服务器要发送的任何数据,否则您应该省略 Accept header 。

阅读RFC 2616了解 HTTP 协议(protocol)的正式定义及其工作原理。

更新:由于您显然是在处理自定义协议(protocol)而不是标准 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);

关于sockets - 使用 curllib 向服务器发送数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23249772/

相关文章:

c++ - Winsock2 选择() : multiple events on the same socket is possible?

http - 需要身份验证的内容的 REST http 状态代码?

c# - 如何在 C# AWS SDK 中强制使用 HTTP-only 模式?

Firebase FCM 使用正确的服务器 key 返回未经授权的错误

curl - 如何在 Windows 上更新 cURL?

php - YouTube 视频搜索与API V3 使用curl 返回错误

java - 从套接字响应中逐字符读取 Kotlin 中的空字符

c - 调整 Linux 上 Web 服务器的接收 ACK 超时

ios - 如何在 iOS 中禁用 HTTP 缓存

sockets - 301 与 socket.http 永久移动