Проблема Socket на С

Модератор: Модераторы разделов

Zloixxx
Сообщения: 10

Проблема Socket на С

Сообщение Zloixxx »

При подключении к недоступному в данный момент урлу скрипт на этапе connect() очень долго висит, а потом вылетает ничего не говоря

...
sock=socket(AF_INET, SOCK_STREAM, 0);
hn=gethostbyname(host);
memcpy(&ssin.sin_addr,hn->h_addr_list[0], hn->h_length);
ssin.sin_family= hn->h_addrtype;
ssin.sin_port= htons((u_short)port);
connect(sock,(struct sockaddr *) &ssin,sizeof(ssin));
send(sock,(char *)request,strlen(request),0);
...

Можно ли сделать и как, что по таймауту (напр. 30 сек) завершалось выполнение connect() и программа не вылетала?
Спасибо сказали:
Аватара пользователя
elide
Бывший модератор
Сообщения: 2421
Статус: Übermensch
ОС: лялих

Re: Проблема Socket на С

Сообщение elide »

используй NONBLOCK сокеты и select.
кстати, про то, что у функций есть возвращаемое значение, тебе в школе не рассказывали?
слава роботам!
Спасибо сказали:
Zloixxx
Сообщения: 10

Re: Проблема Socket на С

Сообщение Zloixxx »

elide писал(а):
24.05.2007 17:57
используй NONBLOCK сокеты и select.
кстати, про то, что у функций есть возвращаемое значение, тебе в школе не рассказывали?

про возвращаемые значения я знаю
долго ждет и вылетает на этом моменте connect(sock,(struct sockaddr *) &ssin,sizeof(ssin));
вот и интересно можноли чтобы по таймауту это операция прекращалась
Спасибо сказали:
Аватара пользователя
BlackStar
Сообщения: 1338
Статус: We are all Kosh
ОС: Fedora 10

Re: Проблема Socket на С

Сообщение BlackStar »

Она и прекращается по таймауту, смотри в сторону setsockopt и параметров SO_RCVTIMEO и SO_SNDTIMEO.

man 7 socket
man 2 setsockopt
LightLang Team
Спасибо сказали:
Аватара пользователя
elide
Бывший модератор
Сообщения: 2421
Статус: Übermensch
ОС: лялих

Re: Проблема Socket на С

Сообщение elide »

SO_RCVTIMEO и SO_SNDTIMEO
это не есть гут. слишком непортабельно.
если я правильно помню, то POSIX 1003.1g draft 6.4 вообще описывал эти опции как read-only.
в draft 6.6 они уже не read-only, но стоит пометка "Note that not all implementations allow this option to be set."
т.е. вообще её использовать можно, но ну его нафиг.
правильно эта задача решается именно через неблокирующие сокеты и поллинг.
слава роботам!
Спасибо сказали:
Zloixxx
Сообщения: 10

Re: Проблема Socket на С

Сообщение Zloixxx »

BlackStar писал(а):
24.05.2007 18:33
Она и прекращается по таймауту, смотри в сторону setsockopt и параметров SO_RCVTIMEO и SO_SNDTIMEO.

man 7 socket
man 2 setsockopt

SO_RCVTIMEO и SO_SNDTIMEO на connect() не производят эффекта
буду пробывать неблокирующие сокеты
Спасибо сказали:
MedVed
Сообщения: 112

Re: Проблема Socket на С

Сообщение MedVed »

Посмотри у Стивенса "Разработка сетевых приложений", глава 15, если память не изменяет, - там есть код функции connect с таймаутом.
Основная идея - сделать сокет неблокирующим, а потом ждать в select'е нужное время.
Что-то вроде этого (на вскидку, не факт, что будет работать):

Код: Выделить всё

int timed_connect(int sock, const sockaddr* addr, int len, int timeout)
{

int flags = ::fcntl(sock, F_GETFL, 0);
::fcntl(sock, F_SETFL, flags|O_NONBLOCK);

int rc = 0;
if (  (rc = ::connect(sock, addr, len))  <  0 )
      if (EINPROGRESS != errno) return -1; // Ошибка!

if (rc == 0) return 0; // Нормально - соединились!

// Не соединились - будем ждать

fd_set fdsRead, fdsWrite;
FD_ZERO(&fdsRead);
FD_ZERO(&fdsWrite);
FD_SET(sock, &fdsRead);
FD_SET(sock, &fdsWrite);

struct timeval wait_time;
wait_time.tv_sec = timeout;
wait_time.tv_usec = 0;

if (  (rc = ::select(sock+1, &fdsRead, &fdsWrite, NULL, &wait_time)  ==  0)
{
        ::close(sock);
        errno = ETIMEDOUT;
        return -1;
}

if ( FD_ISSET(sock, &fdsRead) || FD_ISSET(sock, &fdsWrite) )
{
// Здесь по-идее должен быть код проверки для Solaris, но я его не помню :)
       ::fcntl(sock, F_SETFL, flags);
       return 0;
}

::close(sock);
return -1;

}
МСВС 3.0/Linux Mandrake 8.0
Спасибо сказали: