Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Ошибка неблокируемого connect-а: getsockopt() и connect()  (Прочитано 20408 раз)
0 Пользователей и 1 Гость смотрят эту тему.
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« : 06-07-2003 13:23 » 

Вызвав connect() для неблокируемый сокета получаем EINPROGRESS (конечно речь о TCP). Через select() узнаем когда он будет готов для записи и тут нужно узнать как прошел процесс соединения. Я знаю два способа: вызвать второй раз connect() и getsockopt(...SO_ERROR...). В попытке узнать какой вариант лучше начал копать литературу.

У уважаемого автора (W.R.Stivens) описывается только вариант getsockopt и тут вопросов нет.
Про второй connect() в info libc (glibc) и POSIX 1003.1 написано:
Цитата
Subsequent calls to connect() for the same socket, before the connection is established, shall fail and set errno to [EALREADY].

Я попробовал сделать тест и получил интересный результат. Запускал я на Linux (kernel 2.4.19, glibc-2.2.4).

Код:

/* connect.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void print_err(char *id,int n) {
    if(n==-1) printf("%s: %d, strerror(%d)=\"%s\"\n",id,n,errno,strerror(errno));
    else  printf("%s: %d\n",id,n);
    }

int main(int argc,char **argv) {
    char                        *a,*p;
    struct sockaddr_in          sa;
    int                         fd;
    fd_set                      set;

    if(argc<3) {
        printf("Usage: %s ip_address tcp_port\n",argv[0]);
        return -1;
        }
    a=argv[1];
    p=argv[2];
    printf("Start - %s:%s\n",a,p);
    memset(&sa,0,sizeof(sa));
    sa.sin_family=AF_INET;
    sa.sin_addr.s_addr=inet_addr(a);
    sa.sin_port=htons((unsigned short)atoi(p));
    print_err("socket()",(fd=socket(PF_INET,SOCK_STREAM,0)));
    print_err("fcntl()",fcntl(fd,F_SETFL,O_NONBLOCK{fcntl(fd,F_GETFL,0)));
    print_err("connect()",connect(fd,(struct sockaddr*)&sa,sizeof(sa)));
    FD_ZERO(&set);
    FD_SET(fd,&set);
    print_err("select()",select(fd+1,0,&set,0,0));
    if(FD_ISSET(fd,&set)) print_err("connect()",connect(fd,(struct sockaddr*)&sa,sizeof(sa)));
    close(fd);
    printf("Exit\n");
    return 0;
    }

Сборка:
Код:
$ gcc -Wall -o connect connect.c

Результат:
Код:
$ ./connect 127.0.0.1 200
Start - 127.0.0.1:200
socket(): 3
fcntl(): 0
connect(): -1, strerror(115)="Operation now in progress"
select(): 1
connect(): -1, strerror(111)="Connection refused"
Exit

$ ./connect 127.0.0.1 22
Start - 127.0.0.1:22
socket(): 3
fcntl(): 0
connect(): -1, strerror(115)="Operation now in progress"
select(): 1
connect(): 0
Exit

$ ./connect 1.2.3.4 21
Start - 1.2.3.4:21
socket(): 3
fcntl(): 0
connect(): -1, strerror(115)="Operation now in progress"
rpmselect(): 1
connect(): -1, strerror(110)="Connection timed out"
Exit

Хотелось бы понять - то ли я чего не так почел в POSIX, или в Linux-е connect() работает иначе.
Кто-нибудь может попробовать запустить на иных ОС?
« Последнее редактирование: 18-11-2007 06:35 от Алексей1153++ » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
alteest
Гость
« Ответ #1 : 07-07-2003 05:00 » 

вопрос конечно не совсем по теме:
POSIX - полную доку где достать можно? а то приходится какими-то обрывкамми перебиваться
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 07-07-2003 07:35 » 

Почему же не потеме? *nix!

POSIX тут:
http://www.opengroup.org/onlinepubs/007904975/toc.htm
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #3 : 07-07-2003 08:57 » 

В принципе тема в сети должна была бы попасть Улыбаюсь ну да ладно, пока посмотрим вы что она выльется...

RXL у меня барадак дома на компе в связи с переездом сайта и кучи паролей.
Теперь привожу все в норм. состояние - как только разгребу - поставлю компилятор - тогда посмотрю - так на вскидку вроде все правильно у тебя...
Записан

А птичку нашу прошу не обижать!!!
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 07-07-2003 09:14 » 

Ну мне кажется, что сайт, в основном, посвящен программированию под Win, и посту тут будет лучше. Улыбаюсь

Меня удивляет да же не то что так хорошо работает, а то что в доках про такой случай не описано Я шокирован!
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #5 : 07-07-2003 10:19 » 

Цитата

Ну мне кажется, что сайт, в основном, посвящен программированию под Win, и посту тут будет лучше

Мы боремся с этим   Вот такой я вот
Так что ты не прав...  Жжешь
Записан

А птичку нашу прошу не обижать!!!
DeltaFlight
Гость
« Ответ #6 : 26-10-2003 19:59 » 

Цитата: RXL
У уважаемого автора (W.R.Stivens) описывается только вариант getsockopt и тут вопросов нет.
Про второй connect() в info libc (glibc) и POSIX 1003.1 написано:
Цитата
Subsequent calls to connect() for the same socket, before the connection is established, shall fail and set errno to [EALREADY].
Хотелось бы понять - то ли я чего не так почел в POSIX, или в Linux-е connect() работает иначе.
Кто-нибудь может попробовать запустить на иных ОС?

Дык. Ключевое слово - before. А у тебя второй раз connect зовётся когда connection уже estabilished, то есть after Улыбаюсь

И в мане всё вполне определённо написано:
Код:
       EINPROGRESS
              The socket is non-blocking and the connection  cannot  be
  completed  immediately.   It  is  possible to select(2) or poll(2) for
 completion by selecting the socket for writing. After select indicates
 writability, use getsockopt(2) to  read the SO_ERROR option at level SOL_SOCKET
 to determine whether connect completed successfully (SO_ERROR is zero) or
 unsuccessfully (SO_ERROR is  one of the usual error codes listed here,
 explaining the reason for the failure).

       EALREADY
              The socket is non-blocking and a previous connection attempt has
 not yet been completed.
То есть, рекомендуют использовать SO_ERROR, но никто не говорит, что connect будет давать ошибку после соединения.
« Последнее редактирование: 18-11-2007 06:37 от Алексей1153++ » Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 26-10-2003 20:24 » 

DeltaFlight, получается что "после" он дает код о выполнении операции.
Насчет SO_ERROR понял, буду теперь так...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
DeltaFlight
Гость
« Ответ #8 : 26-10-2003 22:56 » 

Цитата: RXL
DeltaFlight, получается что "после" он дает код о выполнении операции.

А чего ты от него ожидал?
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 27-10-2003 08:39 » 

Все что угодно Отлично В доке прямо не сказано
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
DeltaFlight
Гость
« Ответ #10 : 27-10-2003 12:20 » new

Вот именно. Типичный undefined behavior Улыбаюсь
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines