Просмотр полной версии : C++ функция recv зависает, сокеты, проблема
Пишу в обучающих целях простой граббер web-страниц. Открываю сокет, отсылаю заголовок функцией send. Далее начинается чтение ответа и самого кода странички функцией recv. Тут начинаются проблемы - после чтения предпоследней порции информации функция "переходит в режим ожидания" :( Флаг MSG_PEEK не помогает. Вопрос: как избежать этого виса, возможно ли поставить recv на таймаут? Приведите пожалуйста простой пример кода с решением.
Пока решаю это проблему так: в каждой порции ответа сервера ищу "\r\n\r\n", если нахожу более 2 раз - выход из цикла приема.
Когда я с помощью send-recv работал с вебом, таких проблем не было. Просто я проверял, сколько байт считано (это и возвращает recv), и если это число равно 0, то цикл чтения закончен. Простой пример кода только на асме могу привести, на нем и писал)
Лучше бы показал свой код.
C++ функция recv зависает, сокеты, проблема
Покажи свой код, тут не телепаты...
Я так и пытался делать. Проблема в том, что если размер буфера чуть больше кол-ва оставшихся байт то он пытается что то читать (около минуты функция висит)
вот кусок кода
#define PORT 80
#define SERVERADDR "forum.antichat.ru"
char * connect()
{
WSADATA wd;
char buff[256] = "\0";
char text[100000] = "\0";
char buff2[10000]="GET / HTTP/1.1\r\nHost: forum.antichat.ru\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11\r\nAccept-Language: ru,en-us;q=0.7,en;q=0.3\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n";
printf ( "TCP Client \n" );
if ( WSAStartup ( 0x202, &wd ) )
{
return "[Connection error]";
}
SOCKET sock ;
sock=socket ( AF_INET, SOCK_STREAM, 0 );
if ( sock < 0 )
{
return "[Socket error]";
}
sockaddr_in dest_addr;
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons ( PORT );
HOSTENT *hst;
if( inet_addr(SERVERADDR) != INADDR_NONE )
dest_addr.sin_addr.S_un.S_addr = inet_addr(SERVERADDR);
else if( hst=gethostbyname ( SERVERADDR ) )
( ( unsigned long * ) &dest_addr.sin_addr )[0]=((unsigned long** )hst->h_addr_list)[0][0];
else
{
closesocket( sock ) ;
WSACleanup();
return "[Bad address]";
}
if(connect( sock, (sockaddr *)&dest_addr, sizeof(dest_addr) ))
{
return "[Connection error]";
}
send( sock, buff2, strlen(buff2), 0);
int x = 1;
FILE * ff = fopen("log.txt","w");
while (x>0)
{
x = recv( sock, buff, 256, 0 ); // 256 - buffer size
strcat(text,buff);
fputs(buff,ff);
}
fclose(ff);
return text;
}
Как вариант - использовать не keep-alive соединение, а close. Протокол надо использовать HTTP/1.0, а не 1.1, иначе придется парсить содержимое, так как сервер может отсылать его в этом случае кусками с Transfer-Encoding: chunked. Кстати, в файл надо писать не просто строку buff с помощью fputs, так как последний байт у нее необязательно нулевой, а следует использовать fwrite и явно указывать размер записываемого буфера.
Примерно так:
#define PORT 80
#define SERVERADDR "forum.antichat.ru"
#include "stdio.h"
#include <winsock2.h>
int myconnect()
{
WSADATA wd;
char buff[256] = {0};
char *buff2="GET / HTTP/1.0\r\nHost: forum.antichat.ru\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11\r\nAccept-Language: ru,en-us;q=0.7,en;q=0.3\r\nConnection: close\r\nContent-length: 0\r\n\r\n\n";
printf ( "TCP Client \n" );
if ( WSAStartup ( 0x0101, &wd ) )
{
return 0;
}
SOCKET sock ;
sock=socket ( AF_INET, SOCK_STREAM, 0 );
if ( sock < 0 )
{
return 0;
}
sockaddr_in dest_addr;
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons ( PORT );
HOSTENT *hst;
if( inet_addr(SERVERADDR) != INADDR_NONE )
dest_addr.sin_addr.S_un.S_addr = inet_addr(SERVERADDR);
else if( hst=gethostbyname ( SERVERADDR ) )
( ( unsigned long * ) &dest_addr.sin_addr )[0]=((unsigned long** )hst->h_addr_list)[0][0];
else
{
closesocket( sock ) ;
WSACleanup();
return 0;
}
if(connect( sock, (sockaddr *)&dest_addr, sizeof(dest_addr) ))
{
return 0;
}
send( sock, buff2, strlen(buff2)-1, 0);
int x = 255;
FILE * ff = fopen("log.txt","w");
while (x>0)
{
x = recv( sock, buff, 255, 0 ); // 256 - buffer size
printf("Got %u bytes\n",x);
fwrite(buff,1,x,ff);
}
printf("finished\n",x);
closesocket( sock ) ;
WSACleanup();
fclose(ff);
return 1;
}
int main()
{
myconnect();
return 0;
}
Как вариант - использовать не keep-alive соединение, а close. Протокол надо использовать HTTP/1.0, а не 1.1
Хм, проблема так просто решилась, большое спасибо!
а на счет таймаута для recv в моей статейке почитай
2 _Great_ а если сервак еб*н*тый и непосылает Content-Length - тогда облом. )
При кипелайв соединении обязан. Иначе браузер никогда не узнает когда посылать запрос очередной.
А при клоуз - оно и не нужно.
Хм может еще кто нибудь знает: есть в С++ аналог функции urlencode()? Для преобразования русских символов в url вид?
а самому написать?? банальный конверт в hex с добавлением с переди символа %
например
char *urlencode (char *str) {
char *ret, *ptr;
int len = strlen (str), i;
if ((ret = calloc (3 * len + 1, sizeof (char *))) == NULL)
return NULL;
memset (ret, '\0', len + 1);
for (i = 0, ptr = ret; i < len; i++) {
sprintf ((char *) ptr, "%%%x", str[i]);
ptr += 3;
}
return ret;
}
Хм может еще кто нибудь знает: есть в С++ аналог функции urlencode()? Для преобразования русских символов в url вид?
А с какого ... должен быть?
Я спросил не "почему нету" а "есть ли". Это разные вещи.
awdrg
Если знать, почему может, а почему не может быть, будешь заодно знать и есть ли.
krypt3r
Это что еще за пи##ец?
Откуда sizeof(char*) ?
Почему заполняется нулями только треть буффера - len+1 ?
Зачем вообще заполнение нулями, если вызывается calloc?
Почему код вообще на Си, когда просили на С++?
В чем сакральный смысл приведения char* к тиму char*?
Садись, два
vBulletin® v3.8.14, Copyright ©2000-2026, vBulletin Solutions, Inc. Перевод: zCarot