Как использовать GTK и libcurl одновременно в C? - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь разработать приложение на C с GTK для GUI, libcurl для получения данных с помощью веб-API и cJSON для анализа JSON.

Моя проблема заключается в том, что когда я делаю свой запрос с libcurlпосле gtk_init данные, которые я получаю, не могут быть проанализированы в JSON.В противном случае, если я получу данные и проанализирую их перед gtk_init, синтаксический анализ работает нормально.

У меня есть пример, чтобы продемонстрировать это, первый printf в main возвращает JSON правильно, но второй printf, который идет после gtk_initвозвращает NULL (точнее, анализ останавливается на первом десятичном числе и завершается ошибкой):

initString:

void initString(String * s) {
  s->len = 0;
  s->ptr = malloc(s->len + 1);
  if (s->ptr == NULL) {
    fprintf(stderr, "malloc() failed\n");
    exit(EXIT_FAILURE);
  }
  s->ptr[0] = '\0';
}

writeFunc:

size_t writeFunc(void *ptr, size_t size, size_t nmemb, String * s)
{
  size_t newLen = s->len + size*nmemb;
  s->ptr = realloc(s->ptr, newLen + 1);
  if (s->ptr == NULL) {
    fprintf(stderr, "realloc() failed\n");
    exit(EXIT_FAILURE);
  }
  memcpy(s->ptr + s->len, ptr, size * nmemb);
  s->ptr[newLen] = '\0';
  s->len = newLen;

  return size * nmemb;
}

Моя функция дляполучить данные с помощью libcurl:

char * getData(gpointer user_data)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL * curl;
char * url = user_data;
CURLcode res;
String s;
struct curl_slist * headers = NULL;
curl = curl_easy_init();

if(curl)
{
    initString(&s);

    headers = curl_slist_append(headers, "Accept: application/json");
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, "charsets: utf-8");

    //curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_URL, url);

    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, 6);

    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    //write data in a string
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);

    res = curl_easy_perform(curl);
}

if(res != CURLE_OK)
  fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

curl_easy_cleanup(curl);
return s.ptr;
}

Основное:

int main(int argc, char ** argv)
{
char * str;
cJSON * json;

str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("DATA : %s\n", cJSON_Print(json));//returns the JSON perfectly

gtk_init(&argc,&argv);

str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("ERROR : %s\n", cJSON_GetErrorPtr());//returns half of data
printf("DATA : %s\n", cJSON_Print(json));//returns NULL

gtk_main();

curl_global_cleanup();

return EXIT_SUCCESS;
}

Я попытался решить эту проблему, создав потоки с помощью g_idle_add, gdk_threads_idle_add, gdk_threads_entry и gdk_threads_leave, pthread mixed_create.

Кто-нибудь знает, как решить эту проблему?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 22 февраля 2019

cURL возвращает те же данные до и после, я проверил их, поместив данные в 2 строки, а strcmp возвращает 0.

Действительно, я француз, и между , и * может возникнуть путаница1004 *.

gtk_disable_setlocale решил мою проблему!

0 голосов
/ 22 февраля 2019

Вам нужно сузить свою проблему.Другими словами, вам нужно "M" в MVCE .В настоящее время у вас есть три библиотеки:

  • Gtk +
  • cURL
  • cJSON

, которые могут взаимодействовать произвольным образом.Что нужно проверить:

  • Возвращает ли cURL разные данные до и после gtk_init вызова?Если нет, то проблема не в cURL.

  • Если вы жестко закодировали данные JSON в своей программе и проанализировали их с помощью cJSON, отличаются ли результаты до и после gtk_init?Если так, проблема в cJSON.Если нет, проблема не связана с cJSON.


Мое предположение следующее.gtk_init делает несколько вещей, среди них устанавливает локаль .Поскольку вы выбираете данные из домена .fr, я предполагаю, что на вашем компьютере установлена ​​французская локаль.

, если быть точным, синтаксический анализ останавливается на первом десятичном числе и завершается ошибкой

На французском языке десятичный разделитель - запятая , вместо периода ., поэтому я предполагаю, что после изменения языкового стандарта GTK + cJSON начинает искать , в десятичных числах, но находит . и завершается ошибкой.

Возможные решения

  • В качестве обходного пути позвоните gtk_disable_setlocale до gtk_init.Это может привести к непредвиденным последствиям, например.Ваша программа начинает отображать цифры в английском формате вместо французского в своем пользовательском интерфейсе.

  • Реальным решением было бы выявить ошибку в cJSON, так как при синтаксическом анализе JSON не следует принимать во внимание локаль при синтаксическом анализе.номера. JSON период мандатов . в качестве десятичного разделителя.

0 голосов
/ 22 февраля 2019

Я очень сомневаюсь, что это как-то связано с вызовом gtk_init ().Это звучит как повреждение памяти.Это, вероятно, будет иметь место, например, если вы вернули указатель на данные, которые были выделены, а затем очищены с помощью curl.В этом случае оба вызова неверны, вам просто не повезло с этим в первый раз, так как в этом случае память оставалась нетронутой.Проверьте API для вызовов функций, которые вы делаете.Некоторые выделяют память, которую нужно освободить, другие - нет.

Я предлагаю вам использовать сборку с -g и использовать gdb для проверки вашего кода.Это поможет сузить суть проблемы.Посмотрите и посмотрите, идентичны ли строки.

...