Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
 |
|
C++ функция recv зависает, сокеты, проблема |

17.06.2009, 19:06
|
|
Участник форума
Регистрация: 30.01.2009
Сообщений: 196
Провел на форуме: 505362
Репутация:
66
|
|
C++ функция recv зависает, сокеты, проблема
Пишу в обучающих целях простой граббер web-страниц. Открываю сокет, отсылаю заголовок функцией send. Далее начинается чтение ответа и самого кода странички функцией recv. Тут начинаются проблемы - после чтения предпоследней порции информации функция "переходит в режим ожидания"  Флаг MSG_PEEK не помогает. Вопрос: как избежать этого виса, возможно ли поставить recv на таймаут? Приведите пожалуйста простой пример кода с решением.
Пока решаю это проблему так: в каждой порции ответа сервера ищу "\r\n\r\n", если нахожу более 2 раз - выход из цикла приема.
|
|
|

17.06.2009, 19:33
|
|
Reservists Of Antichat - Level 6
Регистрация: 25.03.2008
Сообщений: 670
Провел на форуме: 4137635
Репутация:
2407
|
|
Когда я с помощью send-recv работал с вебом, таких проблем не было. Просто я проверял, сколько байт считано (это и возвращает recv), и если это число равно 0, то цикл чтения закончен. Простой пример кода только на асме могу привести, на нем и писал)
Лучше бы показал свой код.
|
|
|

17.06.2009, 19:55
|
|
Постоянный
Регистрация: 24.03.2009
Сообщений: 670
Провел на форуме: 2868783
Репутация:
414
|
|
C++ функция recv зависает, сокеты, проблема
Покажи свой код, тут не телепаты...
|
|
|

17.06.2009, 20:01
|
|
Участник форума
Регистрация: 30.01.2009
Сообщений: 196
Провел на форуме: 505362
Репутация:
66
|
|
Я так и пытался делать. Проблема в том, что если размер буфера чуть больше кол-ва оставшихся байт то он пытается что то читать (около минуты функция висит)
вот кусок кода
PHP код:
#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;
}
Последний раз редактировалось awdrg; 17.06.2009 в 20:07..
|
|
|

17.06.2009, 21:20
|
|
Reservists Of Antichat - Level 6
Регистрация: 25.03.2008
Сообщений: 670
Провел на форуме: 4137635
Репутация:
2407
|
|
Как вариант - использовать не keep-alive соединение, а close. Протокол надо использовать HTTP/1.0, а не 1.1, иначе придется парсить содержимое, так как сервер может отсылать его в этом случае кусками с Transfer-Encoding: chunked. Кстати, в файл надо писать не просто строку buff с помощью fputs, так как последний байт у нее необязательно нулевой, а следует использовать fwrite и явно указывать размер записываемого буфера.
Примерно так:
PHP код:
#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;
}
Последний раз редактировалось d_x; 17.06.2009 в 21:25..
|
|
|

17.06.2009, 21:58
|
|
Участник форума
Регистрация: 30.01.2009
Сообщений: 196
Провел на форуме: 505362
Репутация:
66
|
|
Сообщение от d_x
Как вариант - использовать не keep-alive соединение, а close. Протокол надо использовать HTTP/1.0, а не 1.1
Хм, проблема так просто решилась, большое спасибо!
|
|
|

18.06.2009, 00:18
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
а на счет таймаута для recv в моей статейке почитай
|
|
|

18.06.2009, 09:30
|
|
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме: 5339610
Репутация:
4360
|
|
Content-Length!
|
|
|

18.06.2009, 09:52
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
2 _Great_ а если сервак еб*н*тый и непосылает Content-Length - тогда облом. )
|
|
|

18.06.2009, 15:35
|
|
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме: 5339610
Репутация:
4360
|
|
При кипелайв соединении обязан. Иначе браузер никогда не узнает когда посылать запрос очередной.
А при клоуз - оно и не нужно.
|
|
|
|
 |
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|