такая проблемка, хотел сделать многопоточную программку для работы с антикапчей, но код который предлогается на офсайте antigate.com полное г... функции используются глабольные, переменные все глобальные и получается если прога работает в один поток то еще более менее, но если в несколько то полная лажа. вот код имеющегося класса антикапчи PHP: #include <QtGui> #include <c++/iostream> #include <c++/string #include <curl/curl.h> #include <c++/fstream> using namespace std; string contents; string ackey; size_t handle_data(void *ptr, size_t size, size_t nmemb, void *stream) { contents.clear(); int numbytes = size*nmemb; char lastchar = *((char *) ptr + numbytes - 1); *((char *) ptr + numbytes - 1) = '\0'; contents.append((char *)ptr); contents.append(1,lastchar); *((char *) ptr + numbytes - 1) = lastchar; return size*nmemb; } bool myCheckIn(string& HTML, int *pos, string str, bool reg) { if(HTML.size() < *pos + str.size()) return false; for(unsigned int i = 0; i < str.size(); i++) { if(str[i] != HTML[i + *pos]) return false; } *pos += str.size() - 1; return true; } int strpos(string& haystack, const char * needle) { string tmp; tmp=needle; unsigned int hsize = haystack.size(); for (unsigned int i=0;i<hsize;i++) { if (myCheckIn(haystack, (int *) &i,tmp,true)) return (i-tmp.size()+1); } return -1; } string substr(string& str, int pos, int offset) { int i; string res; for (i=pos;i<(pos+offset);i++) { res += str[i]; } return res; } void file_put_contents(char *name, string res) { ofstream fout(name); fout << res; fout.close(); } class Captcha { public: string tempstr; QString unfuck(QString captchafile); }; QString Captcha::unfuck(QString captchafile) { QString captcha; int captcha_id=0; CURL *hCurl = NULL; CURLcode cc; QString text; char error_buffer[1024]; char tmp_char[256]; if (!hCurl) { cc = curl_global_init(CURL_GLOBAL_ALL); hCurl = curl_easy_init(); } if (hCurl) { text = "Sending captcha..."; char *url = "http://antigate.com/in.php"; struct curl_httppost *post=NULL; struct curl_httppost *last=NULL; curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, handle_data); curl_easy_setopt(hCurl, CURLOPT_URL, url); curl_easy_setopt(hCurl, CURLOPT_ERRORBUFFER, &error_buffer); curl_formadd(&post, &last, CURLFORM_COPYNAME, "method", CURLFORM_COPYCONTENTS, "post", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "key", CURLFORM_COPYCONTENTS, ackey.c_str(), CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILE, captchafile.toStdString().c_str(), CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END); curl_easy_setopt(hCurl, CURLOPT_HTTPPOST, post); curl_easy_perform(hCurl); curl_formfree(post); curl_easy_cleanup(hCurl); curl_global_cleanup(); if (strpos(contents,"ERROR")!=-1) { qDebug() << "ERROR!"; return "1"; } QString gg = contents.c_str(); qDebug() << gg; qDebug() << contents.c_str(); tempstr=substr(contents,3,10); qDebug() << tempstr.c_str(); captcha_id=atoi(tempstr.c_str()); if(!captcha_id) { qDebug() << "captcha not load!!"; return "1"; } contents=""; sprintf(tmp_char,"http://antigate.com/res.php?key=%s&action=get&id=%d",ackey.c_str(),captcha_id); qDebug() << "Starting recognize..."; while(1) { Sleep(2000); hCurl = curl_easy_init(); curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, handle_data); curl_easy_setopt(hCurl, CURLOPT_URL, tmp_char); curl_easy_setopt(hCurl, CURLOPT_ERRORBUFFER, &error_buffer); curl_easy_perform(hCurl); curl_easy_cleanup(hCurl); curl_global_cleanup(); if (strpos(contents,"ERROR")!=-1) { return "1"; } if (strpos(contents,"OK")!=-1) { tempstr=substr(contents,3,30); qDebug() << "Recognized captcha: "; qDebug() << tempstr.c_str(); captcha = tempstr.c_str(); break; } contents=""; } } else { } return captcha; } Хотелось бы убрать все эти глобальные функции и переменные, чтобы все было внутри класса, но попробовав сделать эти глобальные функции членнами класса, получается что курл их потом не видит в этой строке PHP: curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, handle_data); я так и не понял как функцию этого же члена класса определить в этой строке, как только не пробывал... понимаю что делаю не так, но прям никак недопрет что именно. кто нить сталкивался с подобной проблемой? или может большой знаток плюсов, посоветуйте как решить проблему плиз...
компилятор выдает error: invalid use of member (did you forget the '&' ?) на эти строки curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, handle_data);
лучше конечно заново написать этот класс, единственное я не пойму какую функцию вот сюда нужно ставить curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, ???); что именно это строка вообще выполняет???
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, ???); этим ты задаешь калбек функцию которая будет каждый раз вызываться при приходе данных с сети. Лично я делал всё не на классах а на по обычному, с учетом того что при ините создавал спец структуру по которой мог определять в келбек функции для какого именно коннекта пришлы данные
удалось переделать)) нужно было эту функцию статично создать)) вот рабочий вариант, еще немного подправить для красоты кода, но уже все рабочее и единственная глобальная переменная это ключь антикапчи, но он и так для всех потоков одинаков так что тут даже лучше что он глобален))
std::string нервно покуривает глазея на методы QString'a =) Раз программа на Qt, мне кажется использование родных для этой библиотеки классов было бы правильней, да и удобней они)
да уж, чет рано я обрадывался)) совсем забыл что статические члены не прокатят для многопоточки)) дело просто в тос что я более менее знаю курл, но совсем не знаю как пользоваться QNetworkAccessManager, поэтому и до сих пор вожусь с курлом. и вы думаете QNetworkAccessManager имеет такую же функциональность как курл? мне где то на форуме кто то ляпнул что он далеко не так мощен как курл... просто интересно мнение тех кто его уже использовал, на сколько он удобен...
а использование курла и в правду очень затрудняет жизнь... если QNetworkAccessManager можно использовать так же хорошо как и курл то думаю конечно будет лучше осваивать его)) но опять же хотелось бы услышать совет от людей знающих побольше меня)
QNetworkAccessManager думаю имеет все, что умеет curl. Однако его использование куда приятнее. Libcurl хорош тем ,что его можно воткнуть практически в любой язык. Соответственно, интеграция с самим языком (и средой) никакая.
да но только хороший программист заточит Libcurl под свое окружение (напишет пачку врапперов) в любом языке и ему будет удобно а с QNetworkAccessManager где сядеш там и слезеш
понятно, спасибо за советы, попробую пока поиспользовать оба варианта, QNetworkAccessManager как новшество для себя ну и курл, то к чему привык и посмотрю разницу) хотя в принципе я всегда собираюсь программировать именно на Qt так как мне он очень нравится, все удобно и развивается достаточно хорошо) попробую переписать класс для разгадки капчи на QNetworkAccessManager, посмотрю что получится... и самое хорошо что документация для QNetworkAccessManager еаписана на русском на кросплатформе, это уже плюс, потому что хоть я и знаю английский, но все же когда читаю на нем то усваиваю далеко не так как если бы читал на русском))
Если писать с Qt, зачем юзать сторонние либы? Когда в нем и так все предусмотрено. Вот я к чему. Мне показалось, либо ты упомянул занятие велопроизводством? =D
а все же как сделать функцию локальной, но не статической, чтобы на нее компилятор не ругался в строке
Файл: PHP: //--------------------------------------------------------------------------- struct CaptchaFile { const char *filename; FILE *stream; }; //--------------------------------------------------------------------------- static size_t CaptchaWrite(void *buffer, size_t size, size_t nmemb, void *stream) { struct CaptchaFile *out=(struct CaptchaFile *)stream; if(out && !out->stream) { out->stream=fopen(out->filename, "wb"); if(!out->stream) return -1; } return fwrite(buffer, size, nmemb, out->stream); } //--------------------------------------------------------------------------- PHP: struct curl_httppost *post=NULL; struct curl_httppost *last=NULL; curl_formadd(&post, &last, CURLFORM_COPYNAME, "method", CURLFORM_COPYCONTENTS, "post", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "soft_id", CURLFORM_COPYCONTENTS, "5", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "key", CURLFORM_COPYCONTENTS, apikey.c_str(), CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILE, filename.c_str(), CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END); curl_easy_setopt(curl, CURLOPT_URL, "http://antigate.com/in.php"); curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); curl_easy_perform(curl); Память: PHP: //--------------------------------------------------------------------------- static void *cap_realloc(void *ptr, size_t size) { return ptr ? realloc(ptr, size) : malloc(size); } //--------------------------------------------------------------------------- struct CaptchaBuffer { char* memory; size_t size; }; //--------------------------------------------------------------------------- static size_t CaptchaWrite(void *data, size_t size, size_t nmemb, void *buffer) { size_t realsize = size * nmemb; struct CaptchaBuffer *mem = (struct CaptchaBuffer *)buffer; mem->memory = (char*)cap_realloc(mem->memory, mem->size + realsize + 1); if(mem->memory) { memcpy(&(mem->memory[mem->size]), data, realsize); mem->size += realsize; mem->memory[mem->size] = 0; } return realsize; } //--------------------------------------------------------------------------- PHP: String VK::AntigateCheckCaptcha() { setopt(curl, CURLOPT_HEADER , 0); setopt(curl, CURLOPT_PROXY , ""); setopt(curl, CURLOPT_PROXYTYPE , HTTP); struct curl_httppost *post = NULL; struct curl_httppost *last = NULL; formadd(&post, &last, CURLFORM_COPYNAME, "method", CURLFORM_COPYCONTENTS, "post", CURLFORM_END); formadd(&post, &last, CURLFORM_COPYNAME, "soft_id", CURLFORM_COPYCONTENTS, "5", CURLFORM_END); formadd(&post, &last, CURLFORM_COPYNAME, "key", CURLFORM_COPYCONTENTS, sAntigateKey, CURLFORM_END); formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "captcha.jpg", CURLFORM_BUFFERPTR, bufCaptcha.memory, CURLFORM_BUFFERLENGTH, bufCaptcha.size, CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END); String sId = ""; sUrl = "http://antigate.com/in.php"; sPage = ""; setopt(curl, CURLOPT_URL, sUrl); setopt(curl, CURLOPT_HTTPPOST, post); perform(curl); setopt(curl, CURLOPT_POST, 0); formfree(post); if(sPage.Pos("\r")) sPage.SetLength(sPage.Pos("\r") - 1); if(sPage.IsEmpty()) return "ERROR_REPLY_IN"; else if(sPage.Pos("ERROR_")) return sPage; else if(sPage.Pos("OK")) sId = sPage.SubString(sPage.Pos("|") + 1, sPage.Length() - sPage.Pos("|")); if(sId.IsEmpty()) return "ERROR_BAD_CAPTCHA_ID"; for(int i = 0; i < 12; ++i) { Sleep(5000); sUrl = "http://antigate.com/res.php?key=" + sAntigateKey + "&action=get&id=" + sId; sPage = ""; setopt(curl, CURLOPT_URL, sUrl); perform(curl); if(sPage.Pos("\r")) sPage.SetLength(sPage.Pos("\r") - 1); if(sPage.IsEmpty()) return "ERROR_REPLY_GET"; else if(sPage.Pos("ERROR_")) return sPage; else if(sPage.Pos("OK")) { sPage.Delete(1, sPage.Pos("|")); return sPage; } } return "ERROR_TIMEOUT"; }
спасибо большое. пробую сделать класс для работы на QNetworkAccessManager но нифига не пойму одного, вот сделал такой код: net.h net.cpp и вот вызов
по идее exec() должен вернуть buffer с данными, он он гад ничего не возращает, причем в слоте загрузка производится, но exec() завершается до того как произойдет вывод reply в buffer. В чем же проблема???
хотел спросить у M_script, ты такой код в многопоточных программах используешь? мне просто интересно у тебя капча в один и тот же файл сохраняется, а как быть если к примеру 10 потоков обратятся к разгадке капчи, получается они перезапишут файл captcha.jpg и разгадка будет неверной или я ошибаюсь?