привет все. пытаюсь получить страницу ya.ru. все бы ничего запрс ушел ответ приходит. но в нем куча мусора который постоянно повторяется. вот кусок кода Code: int get_page (char *buf) { SOCKET sock; char buff[8024]; int len; if (!(sock = init_tcp_client("ya.ru", 80))) // инициазизация сокета return 0; len = sprintf(buff, "GET / HTTP/1.1\r\n" "Host: ya.ru\r\n" "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8\r\n" "Accept: text/html,q=0.9,*/*;q=0.8\r\n" "Accept-Language: ru,en-us;q=0.7,en;q=0.3\r\n" "Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7\r\n" "Keep-Alive: 115\r\n" "Connection: keep-alive\r\n" "\r\n"); len=send(sock, buff, len,0); // передача запроса len=recv(sock, buff, len,0); while (len>0) { printf(buff); len=recv(sock, buff, len,0); } //memcpy(buf,buff,sizeof(buff)); close(sock); return len; }
Так делать нельзя, потому что printf выводит buff как строку, а recv принимает как бинарные данные. Соттветственно, строка будет не законченной нуллбайтом и при вызове printf вывалится еще куча мусора до первого попавшегося нуллбайта. Нужно принимать сразу все данные в буфер, а потом уже выводить их, не забыв дописать в конец нулевой байт.
GRRRL Power проблема в том что я незнаю заранее размер страници чтоб под нее выделить буфер. да и не догоняю как например к уже выделенной паменить добавть еще тогда было бы проще
сделал так Code: tmp=malloc(1024*32); t_tmp=tmp; len=send(sock, buff, len,0); // передача запроса len=recv(sock, buff, len,0); while (len>0) { //printf(buff); memcpy(t_tmp,buff,len); t_tmp=t_tmp+len; len=recv(sock, buff, len,0); } printf(tmp);
Как вариант: PHP: size_t received_len, len = 0; //... do { len = recv(sock, (char*)&buff[0] + received_len, len, 0); received_len += len; } while(len > 0); buff[received_len] = 0; printf(buff); Размер буфера узнается из заголовков, в http-заголовке Content-length это пишется, поэтому нужно сначала принять его, спарсить длину, создать буфер и читать. Либо же париться с выделениями памяти. За нас это уже сделали, поэтому можно написать: PHP: #include <string> using std::string; //... size_t len = 0; char buff[1024]; string str = ""; //... do { len = recv(sock, buff, 1023, 0); buff[len] = 0; str.append(buf); } while(len > 0); printf("%s", str.c_str()); //опасно так выводить Коды не проверял, но должно работать.
спасибо за помошь. ну я почти так же сделал =) ну да можно парсить а можно выделить сразу здоровый кусок кода.
Во втором примере мы не работаем с памятью, все делает класс string. Если много контента будет получено, то несколько раз строка будет копироваться из одного буфера памяти в другой, большего размера, но мы этого не видим, это всё внутри string происходит.
Code: do { len = recv(sock, buff, 1023, 0); buff[len] = 0; str.append(buf); } while(len > 0); Так нельзя. Потому что если вдруг коннект разорвется и recv вернет -1 то затрется переменная перед массивом. Code: do { len = recv(sock, (char*)&buff[0] + received_len, len, 0); received_len += len; } while(len > 0); Так тож незя, потому что по темже причинами, тока тут ты уменьшиш размер данных котоыре считал. А вот если ты заранее выделил большой буфер, то можно вот так вот сделать: Code: int full_len = 0; for (;;) { len = recv (sock, buf + full_len, buf_len - full_len - 1, 0); if (len < 1) break; full_len += len; } buf[full_len] = 0; В итоге у тебя не будет переполнения буфера и нормально обработается дисконнект или ошибка. И в конце при любом условии ты поставишь нулбайт где надо.
Просто добавить условие выхода из цикла при len == -1. Содержимое всегда может быть больше по объему, чем выделенный буфер, и часть останется непринятой) Не выделять же мегабайтами заранее.
2GRRRL Power угу а еще если в buff встретиться % то вообще красота начнется я бы так написал printf("%s\n", buff); или так printf("%.*s\n", len, buff); если известна длинна строки но она без '\0' в конце 2slesh Code: int full_len = 0; for (;;) { len = recv (sock, buf + full_len, buf_len - full_len - 1, 0); if (len < 1) break; full_len += len; } buf[full_len] = 0; красивый код 2transserg Code: typedef char page; page * alloc_page(unsigned sock) { char buff[4096], *tmp; page *p = 0; int rec, all = 0; do { rec = recv(sock, buff, sizeof(buff), 0); if (rec == -1) { free(p); return NULL; } if (rec > 0) { all += rec; tmp = realloc(p, all + 1); if (!tmp) { free(p); return NULL; } p = tmp; memmove(p + all - rec, buff, rec); p[all] = '\0'; } } while (rec > 0); return p; } void free_page(page *p) { free(p); }
Code: typedef char page; page * alloc_page(unsigned sock) { char buff[4096], *tmp; page *p = 0; int rec, all = 0; do { rec = recv(sock, buff, sizeof(buff), 0); if (rec == -1) { free(p); return NULL; } if (rec > 0) { all += rec; [SIZE=4][COLOR=DarkRed]tmp = realloc(p, all + 1);[/COLOR][/SIZE] if (!tmp) { free(p); return NULL; } p = tmp; memmove(p + all - rec, buff, rec); p[all] = '\0'; } } while (rec > 0); return p; } void free_page(page *p) { free(p); } error C2440: '=' : cannot convert from 'void *' to 'char *'
2cheater_man 2Irdis просто это C код а не C++ надо включить опцию /TC в компиляторе C/C++->Advanced->Compile As->Compile As C Code(/TC) что значит что собирать как ANSI C в нем неявное приведение из void* в любой другой тип абсолютно корректно в отличии от C++ для C++ можно просто закастить
и что? и где у тя free будет если по мсдну "If the connection has been gracefully closed, the return value is zero" а бред пардон надо трезветь
не мог бы проект целиком куда-нибудь залить, а то если как С компилю то: Error 1 error LNK2019: unresolved external symbol _recv@16 referenced in function _alloc_page 123456.obj Error 2 fatal error LNK1120: 1 unresolved externals
проекта нет и небыло никогда это писалось еще когда slesh писал утилитку для slil.ru just for fun просто можно сделать так #pragma comment(lib, "ws2_32.lib") или Linker->Input->Additional Dependencies->ws2_32.lib