The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Эксперимент с неблокирующимися сокетами (block socket gcc example)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: block, socket, gcc, example,  (найти похожие документы)
Date: Wed, 05 Mar 2003 09:53:51 +0500 From: Valentin Nechayev <netch@segfault.kiev.ua> Newsgroups: ftn.ru.unix.prog Subject: Эксперимент с неблокирующимися сокетами >> Я уже посоветовал. Про треды ничего сказано не было. AP> Угу. А если у меня уже взведён другой обработчик алармов? аларм -- криво как AP> ни крути. Случай другого обработчика, кажется, рассмотрен в sendmail'е, там это обходится через setitimer() сохранением старого состояния и восстановлением по сигналу. В общем, методы есть. >> А вообще, повтори plz ещё раз ситуацию. Ты хочешь, чтобы на сокете, >> который или ещё не прошёл connect(), или уже не прошёл (refused, и тому >> подобное), read() выдавал что-то осмысленное? AP> Я хочу быть уверенным, что неблокирующийся сокет прошёл коннект. Вроде AP> приведённый мной код должен делать именно это. Если 1) сокет сделан неблокирующим, 2) сделан connect(), 3) дождались возможности записи, и вот тут возникает проблема определить, получился успешный коннект или нет? Проверка на неблокируемость чтения и записи проходит на оба успешно, потому что они потом вылетят с ошибкой? Я правильно описал, чего ты хочешь? Вот отчёт теста (код - ниже): netch@iv:~/prog/tests/sockets/connect>./c scheck(RW): after poll: not ready for anything now is 1046846925:031937 on connect: -1,36 c: getpeername: Socket is not connected now is 1046846925:032188 Connect is in progress scheck(RW): after poll: not ready for anything sget: -1,Resource temporarily unavailable(35) now is 1046846925:032241 scheck(RW): after poll: ready for write sget: -1,Resource temporarily unavailable(35) now is 1046846925:170563 peer: 0xC1C1C104:22 scheck(R): after poll: ready for read sget: 40,Resource temporarily unavailable(35) now is 1046846925:307460 Вот tcpdump к этому: 1046846925.032031 193.193.199.34.1046 > 193.193.193.4.22: S 1949113222:1949113222(0) win 57344 <mss 1460> (DF) 1046846925.169908 193.193.193.4.22 > 193.193.199.34.1046: S 518759507:518759507(0) ack 1949113223 win 57344 <mss 1460> (DF) 1046846925.169970 193.193.199.34.1046 > 193.193.193.4.22: . ack 1 win 58400 (DF) 1046846925.306852 193.193.193.4.22 > 193.193.199.34.1046: P 1:41(40) ack 1 win 58400 (DF) 1046846925.307544 193.193.199.34.1046 > 193.193.193.4.22: F 1:1(0) ack 41 win 58400 (DF) 1046846925.435266 193.193.193.4.22 > 193.193.199.34.1046: . ack 2 win 58400 (DF) 1046846925.444044 193.193.193.4.22 > 193.193.199.34.1046: F 41:41(0) ack 2 win 58400 (DF) 1046846925.444069 193.193.199.34.1046 > 193.193.193.4.22: . ack 42 win 58400 (DF) Видно, что: 1. Прямым критерием того, что коннект есть, является положительный ответ getpeername(). 2. По connect() ушёл SYN, готовности нет ни к чему, а мы пошли в спячку. getpeername() пока говорит, что ничего нет. Спячка заканчивается приходом пакета SYN+ACK, после чего немедленно возникает готовность к записи. 3. Готовность к чтению возникает уже на четвёртом пакете - когда со стороны сервера прошёл PSH+ACK с данными (в котором SSH'евый баннер; я уже не буду включать показ данных - по отчёту видно, что прибежало 40 байт). То есть, я бы советовал тебе после готовности к записи сделать getpeername() и по её ответу понять, что же у нас такое. Hепонятно, что ты говорил про то, что recv() возвращает 0. Странно это. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <fcntl.h> #include <poll.h> #include <sys/time.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <err.h> void scheck( int s, int timeo, const char* e ) { struct pollfd pf; int rc; pf.fd = s; pf.events = 0; if( strchr( e, 'R' ) ) pf.events |= POLLRDNORM; if( strchr( e, 'W' ) ) pf.events |= POLLWRNORM; rc = poll( &pf, 1, timeo ); if( rc == -1 ) warn( "poll" ); if( pf.revents & POLLHUP ) printf( "after poll: hup\n" ); else if( pf.revents & POLLRDNORM ) { if( pf.revents & POLLWRNORM ) printf( "scheck(%s): after poll: ready for read and write\n", e ); else printf( "scheck(%s): after poll: ready for read\n", e ); } else { if( pf.revents & POLLWRNORM ) printf( "scheck(%s): after poll: ready for write\n", e ); else printf( "scheck(%s): after poll: not ready for anything\n", e ); } } void showpeer( int s ) { struct sockaddr_in si; socklen_t sil; int r; sil = sizeof si; r = getpeername( s, ( struct sockaddr* ) &si, &sil ); if( r < 0 ) { warn( "getpeername" ); return; } printf( "peer: 0x%08X:%d\n", (unsigned) ntohl( si.sin_addr.s_addr ), (int) ntohs( si.sin_port ) ); } void ptime() { struct timeval tv; gettimeofday( &tv, NULL ); printf( "now is %lu:%06lu\n", tv.tv_sec, tv.tv_usec ); } void sget( int s ) { char buf[100]; int rc, se; rc = read( s, buf, sizeof buf ); se = errno; printf( "sget: %d,%s(%d)\n", rc, strerror(se), se ); } int main() { int s, ff, rc, se; struct sockaddr_in sia; s = socket( AF_INET, SOCK_STREAM, 0 ); if( s == -1 ) err( 1, "socket()" ); ff = fcntl( s, F_GETFL, 0 ); if( ff == -1 ) err( 1, "F_GETFL" ); if( fcntl( s, F_SETFL, O_NONBLOCK | ff ) == -1 ) err( 1, "F_SETFL" ); memset( &sia, 0, sizeof sia ); sia.sin_family = AF_INET; sia.sin_port = htons( 22 ); sia.sin_addr.s_addr = htonl( 0x7F000001 ); sia.sin_addr.s_addr = htonl( 0xC1C1C104 ); Connect: scheck( s, 0, "RW" ); ptime(); rc = connect( s, ( struct sockaddr* ) & sia, sizeof sia ); se = errno; printf( "on connect: %d,%d\n", rc, se ); showpeer( s ); ptime(); if( rc == -1 && se == EINTR ) goto Connect; if( rc == 0 ) { printf( "connect: ok immediately\n" ); scheck( s, 0, "RW" ); showpeer( s ); return 0; } if( rc == -1 && se != EINPROGRESS ) errc( 1, se, "connect" ); if( rc == -1 && se == EINPROGRESS ) { printf( "Connect is in progress\n" ); scheck( s, 0, "RW" ); sget( s ); ptime(); scheck( s, 10000, "RW" ); sget( s ); ptime(); showpeer( s ); scheck( s, 10000, "R" ); sget( s ); ptime(); } return 0; } -netch-

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

Обсуждение [ RSS ]
  • 1, sergio (??), 20:04, 09/06/2004 [ответить]  
  • +/
    вся эта тема полностью раскрыта Бернштейном, например в QMail.
    читать http://cr.yp.to/unix/nonblock.html
    к этому вряд-ли можно что-то добавить.

    еще в качесте примера, можно посмотреть исходники postfix src/util/timed_(read|write|connect).c

     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Спонсоры:
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2021 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру