如何在持久连接中使用 libcurl 发送数据?

How to send data with libcurl in persistent connections?

我正在使用 libcurl 连接到 LightStreamer 服务器。考虑以下最小示例:

#include <curl/curl.h>

static size_t writeCallback(char *ptr, size_t size, size_t nmemb, void* userdata)
{
        printf("%.*s\n", size * nmemb, ptr);
        return size * nmemb;
}

int main() {
        const char url[] =
        "http://push.lightstreamer.com/lightstreamer/create_session.txt?LS_protocol=TLCP-2.0.0";
        const char data[] =
        "LS_adapter_set=DEMO&LS_cid=mgQkwtwdysogQz2BJ4Ji%20kOj2Bg";

        CURL *curl = curl_easy_init();

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);

        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(data));

        curl_easy_perform(curl);

        return 0;
}

当运行这个时候,服务器永远不会关闭连接;这意味着 curl_easy_perform 永远不会 returns.

但是,我需要在同一个连接上向服务器传输数据,例如订阅数据项。但是根据我对 curl 文档的理解,我不应该在第一个 perform 仍然是 运行.

时第二次调用 curl_easy_perform

这是如何实现的?我查看了 multi 接口的文档,但我不确定这是否是我需要的。

#include <curl/curl.h>

static size_t writeCallback(char *ptr, size_t size, size_t nmemb, void* userdata) {
  printf("%.*s\n", size * nmemb, ptr);
  return size * nmemb;
}

static size_t headerCallback(char *buffer, size_t size, size_t nitems, void *userdata) {
  int *keep_running = (int *)userdata;
  if (nitems * size == 2 && !strncmp(buffer, "\r\n", 2))
    *keep_running = 0;
  return nitems * size;
}

int main() {
  const char url[] =
        "http://push.lightstreamer.com/lightstreamer/create_session.txt?LS_protocol=TLCP-2.0.0";
  const char data[] =
        "LS_adapter_set=DEMO&LS_cid=mgQkwtwdysogQz2BJ4Ji%20kOj2Bg";

  CURL *curl = curl_easy_init();

  int keep_running = 1;  // keep running until response headers received

  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, &keep_running);
  curl_easy_setopt(curl, CURLOPT_URL, url);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(data));

  CURLM *multi_handle = curl_multi_init();
  curl_multi_add_handle(multi_handle, curl);

  CURLMcode mc;
  int still_running = 1;  // keep number of running handles
  do {
    mc = curl_multi_perform(multi_handle, &still_running);
 
    if (!mc) {
      // wait for activity, timeout or "nothing"
      mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
    }
    if(mc) {
      fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc);
      break;
    }
  } while(keep_running && still_running);
    
  int queed = 0;
  CURLMsg *msg = curl_multi_info_read(multi_handle, &queed);
  if (msg && (msg->msg == CURLMSG_DONE)) {
    // request finished
    CURLcode rc = msg->data.result;
  } else if (!mc) {
    // request is alive
    curl_socket_t sockfd;
    if (!curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd)) {
      do {
        if (write(sockfd, "OK\r\n", 4) < 0)
          break;
        
        // keep alive
        CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
        if(mc)
          break;
      } while (still_running);
    }
  }

  curl_multi_remove_handle(multi_handle, curl);
  curl_easy_cleanup(curl);
  curl_multi_cleanup(multi_handle);

  curl_global_cleanup();
  return 0;
}