libcurl задерживается на 1 секунду перед загрузкой данных, curl из командной строки не
Я использую libcurl для отправки команды API в локальную службу (т.е. на 127.0.0.1).
Программа предназначена для замены сценария оболочки (который использует curl
программа).
Все работает, за исключением того, что где-то есть 1-секундная задержка, т.е. 1 секунда истекает со времени, когда я звоню curl_easy_perform()
когда моя функция обратного вызова read впервые вызывается.
Программа на C использует эти параметры (проверка ошибок и код обратного вызова опущены):
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:12345/x");
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, (long)getLengthOfCommandObject());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &myReadFunction);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &myWriteFunction);
Но если я бегу curl
из скорлупы вот так:
$ curl --data-binary '<command>' http://127.0.0.1:12345/x
он отправляет запрос немедленно, не страдая от 1-секундной задержки.
Что может быть причиной задержки, и есть ли опция, которую я могу установить, чтобы предотвратить ее?
Редактировать сервер основан на мангусте
3 ответа
Причина задержки была:
- libcurl отправлял
Expect: 100-Continue
заголовок - Сервер (основанный на mongoose) не настроен на отправку
100 Continue
ответы автоматически. - libcurl ожидает до 1 секунды этого ответа. Если он не получит его по истечении этого времени, он все равно отправляет тело запроса.
Решение на стороне клиента - отключить Expect
заголовок вроде так:
headers = curl_slist_append(NULL, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// ...
result = curl_easy_perform(curl);
curl_slist_free_all(headers);
Эквивалентное исправление для клиента PHP и связанный с ним вопрос PHP
Этот ответ не является ответом, но показывает, в чем проблема. У меня была такая же проблема с
libcurl
против
Civet
который основан на
mongoose
.
У меня была такая же проблема, и я попытался отладить ее. Это результат
strace
(с меткой времени в секундах в каждой строке). Проблема в том, что существует последовательность
poll( ...events=POLLIN...)
вызывает этот блок в течение 1000 миллисекунд (1+98+1+900) после отправки заголовка, до отправки тела. Вы можете увидеть разрыв во временных метках с 17.935024 до 18.931842.
17.934881 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 5
17.934898 fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)
17.934916 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0
17.934934 connect(5, {sa_family=AF_INET, sin_port=htons(37034), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
17.934952 poll([{fd=5, events=POLLOUT|POLLWRNORM}], 1, 0) = 1 ([{fd=5, revents=POLLOUT|POLLWRNORM}])
17.934970 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
17.934988 getpeername(5, {sa_family=AF_INET, sin_port=htons(37034), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
17.935006 getsockname(5, {sa_family=AF_INET, sin_port=htons(46830), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0
17.935024 sendto(5, "POST /foo/1/bar HTTP/"..., 168, MSG_NOSIGNAL, NULL, 0) = 168
17.935042 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
17.935060 poll([{fd=5, events=POLLIN}], 1, 1) = 0 (Timeout)
17.935078 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
18.029421 poll([{fd=5, events=POLLIN}], 1, 98) = 0 (Timeout)
18.029518 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
18.030576 poll([{fd=5, events=POLLIN}], 1, 1) = 0 (Timeout)
18.030681 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
18.931571 poll([{fd=5, events=POLLIN}], 1, 900) = 0 (Timeout)
18.931642 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
18.931698 poll([{fd=5, events=POLLIN}, {fd=5, events=POLLOUT}], 2, 1000) = 1 ([{fd=5, revents=POLLOUT}])
18.931726 poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}, {fd=5, events=POLLOUT|POLLWRNORM}], 2, 0) = 1 ([{fd=5, revents=POLLOUT|POLLWRNORM}])
18.931842 sendto(5, "{\"foo\":[{\"bar\":\"A\",\"e"..., 1642, MSG_NOSIGNAL, NULL, 0) = 1642
У меня была такая же проблема с командной строкой
curl
а также с
curl_easy_perform
, но у меня не было проблем с использованием другого клиента REST, такого как Postman.
Благодаря ответу @finnw и обсуждению здесь (https://groups.google.com/g/mongoose-users/c/92fD1Elk5m4?pli=1) мне удалось исправить CivetWeb для поддержки
100-continue
функцию со следующим (см.
#ifdef DEXPECT_100_CONTINUE_FIX
).
void
CivetServer::getPostData(struct mg_connection *conn, std::string& dst)
{
struct mg_request_info *ri = mg_get_request_info(conn);
assert(ri != NULL);
CivetServer *me = (CivetServer*) (ri->user_data);
assert(me != NULL);
mg_lock_context(me->context);
CivetConnection &conobj = me->connections[conn];
mg_lock_connection(conn);
mg_unlock_context(me->context);
#ifdef EXPECT_100_CONTINUE_FIX
const char * expect_str = mg_get_header(conn, "Expect");
if (expect_str)
{
printf("CivetServer::getParam, Expect:%s\n", expect_str);
if (strcmp(expect_str,"100-continue") == 0)
{
mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
}
}
else
{
printf("CivetServer::getParam, Expect: blank\n");
}
#endif