【发布时间】:2021-08-04 08:28:26
【问题描述】:
目标:
仅在检测到某个HTTP status code(例如200)时才打印多路复用响应的内容。这需要在回调函数收到响应时读取标头并提取 HTTP 代码。
由于多路复用接收到的响应可以通过回调方法以任意顺序返回给程序,因此必须异步/以非阻塞方式查找此状态码。
下面看到的程序基于libcurl tutorial found here。包含有关HTTP multiplexing can be found here. 信息的问题
问题:
程序成功地异步发送请求,接收,然后打印响应,但我目前不确定在程序中的哪个位置使用curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code),或者这是否是multi interface 程序在查找时的正确方法HTTP status code。
当前输出:
程序打印到stdout 完整的标头和有效负载,但是当使用上述CURLINFO_RESPONSE_CODE 时,程序的行为是同步的(即每次收到从标头到有效负载的任何信息时,程序都会打印响应代码(而它只有当回调函数dump(...)检测到它时才应该打印它。
代码:
#include <stdlib.h>
#include <errno.h>
#include <iostream>
#include <string>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>
#ifndef CURLPIPE_MULTIPLEX
#define CURLPIPE_MULTIPLEX 0
#endif
struct transfer {
CURL *easy;
unsigned int num;
FILE *out;
};
#define NUM_HANDLES 1000
static void dump(const char *text, int num, unsigned char *ptr, size_t size,
char nohex)
{
// Print the response
for (int i = 0; i < size; i++) {
std::cout << ptr[i];
}
}
static int my_trace(CURL *handle, curl_infotype type,
char *data, size_t size,
void *userp)
{
const char *text;
struct transfer *t = (struct transfer *)userp;
unsigned int num = t->num;
(void)handle; /* prevent compiler warning */
switch(type) {
default: /* in case a new one is introduced to shock us */
return 0;
case CURLINFO_SSL_DATA_OUT:
text = "=> Send SSL data";
break;
case CURLINFO_HEADER_IN:
text = "<= Recv header";
break;
case CURLINFO_DATA_IN:
text = "<= Recv data";
break;
case CURLINFO_SSL_DATA_IN:
text = "<= Recv SSL data";
break;
}
dump(text, num, (unsigned char *)data, size, 1);
return 0;
}
static void setup(struct transfer *t, int num)
{
char filename[128];
CURL *hnd;
hnd = t->easy = curl_easy_init();
curl_msnprintf(filename, 128, "dl-%d", num);
t->out = fopen(filename, "wb");
if(!t->out) {
std::cout << "ERROR: could not open file for writing" << std::endl;
exit(1);
}
/* write to this file */
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t->out);
/* set the same URL */
curl_easy_setopt(hnd, CURLOPT_URL, "https://sometesturl.xyz");
/* please be verbose */
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, t);
/* HTTP/2 please */
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
/* we use a self-signed test server, skip verification during debugging */
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
#if (CURLPIPE_MULTIPLEX > 0)
/* wait for pipe connection to confirm */
curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
#endif
}
/*
* Download many transfers over HTTP/2, using the same connection!
*/
int main(int argc, char **argv)
{
struct transfer trans[NUM_HANDLES];
CURLM *multi_handle;
int i;
int still_running = 0; /* keep number of running handles */
int num_transfers;
if(argc > 1) {
/* if given a number, do that many transfers */
num_transfers = atoi(argv[1]);
if((num_transfers < 1) || (num_transfers > NUM_HANDLES))
num_transfers = 3; /* a suitable low default */
}
else
num_transfers = 3; /* suitable default */
/* init a multi stack */
multi_handle = curl_multi_init();
for(i = 0; i < num_transfers; i++) {
setup(&trans[i], i);
/* add the individual transfer */
curl_multi_add_handle(multi_handle, trans[i].easy);
}
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
do {
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
if(still_running)
/* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
if(mc)
break;
} while(still_running);
// This behaves in a blocking / synchronous manner...
// Not sure if this is the correct place to extract the status code?
for (int i = 0; i < num_transfers; i++) {
long response_code; // test variable
curl_easy_getinfo(trans[i].easy, CURLINFO_RESPONSE_CODE, &response_code);
}
for(i = 0; i < num_transfers; i++) {
curl_multi_remove_handle(multi_handle, trans[i].easy);
curl_easy_cleanup(trans[i].easy);
}
curl_multi_cleanup(multi_handle);
return 0;
}
总结性问题:
1. 当使用multiplexing 可以以任何顺序接收响应时,如何使用 libcurl 提取 HTTP 状态代码,以便可以像当前正在接收响应一样异步找到它作为?
【问题讨论】:
-
虽然呈现为 C++ 问题:您需要对其进行重组。用 C++ 包装漂亮的
libcurl库不会使您面临的任何问题隐藏在大量代码块中。全部使用 C++,它会更容易诊断。 -
感谢您的帮助 - 您的意思是我在这里错误地混合了 C 和 C++ 还是我错过了您的意思?
-
不,你是对的。以 RAII 方式限制每一项资产,并让其通过上述方式销毁。
标签: c++ curl libcurl http2 multiplexing