выбор неблокирующего сокета возвращает 1 после подключения - PullRequest
2 голосов
/ 07 декабря 2011

Прежде всего, я хотел бы сказать, что это другая проблема, чем эта: Схожая, но не та же самая

Мой код выглядит так:

struct addrinfo hints, *res;
struct sockaddr* serveraddr;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

int res2 = getaddrinfo(ip, port, &hints, &res);
printf("getaddrinfo() res: %d, %d\n", res2, errno);

serveraddr = res->ai_addr;

//create new socket

int soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("socket() res: %d, %d\n", socket, errno);

//set nonblocking mode
unsigned long on = 1;
res2 = ioctl(soc, FIONBIO, &on);
printf("ioctl() res: %d\n, %d", res2, errno);

res2 = connect(soc, serveraddr, sizeof(struct sockaddr));
printf("connect() res: %d, %d\n", res2, errno);

//check if socket is ready
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(soc, &wfds);

struct timeval t;
t.tv_sec=15;
t.tv_usec=0;

res2 = select(soc + 1, 0, &wfds, 0, &t);
printf("select() res: %d, %d\n", res2, errno);`

Я подключаюсь к существующей машине (IP-адрес существует, но сервер не прослушивает порт, к которому я пытаюсь подключиться).

Выбрать всегда возвращает 1. Почему? По словам человека, он должен тайм-аут и вернуть 0. После этого, когда я пытаюсь что-то записать в сокет, он возвращает -1 / ECONNREFUSED.

Это ожидаемое поведение? Если да, как проверить, что после select () мы подключены?

Ответы [ 2 ]

8 голосов
/ 07 декабря 2011

Я не знаю, где на страницах руководства вы видите, что должно истечь время ожидания.

Если брандмауэр не сбрасывает пакеты, соединение будет отклонено довольно быстро (один пакет с вашего хоста,один пакет ответа).Таким образом, «событие» на соединительном разъеме будет происходить, как только будет получен сброс.Это приведет к пробуждению select с (как минимум) одним активным сокетом.

Первая попытка чтения или записи в этот сокет вернет основную ошибку соединения.

1 голос
/ 27 декабря 2012

Это правильное поведение , поскольку ожидающая ошибка приводит к тому, что сокет становится читаемым и доступным для записи.Как и при любом другом системном вызове, вам необходимо явно проверить наличие ошибок.Вы можете включить сокет в исключение fdset (четвертый аргумент для select ()) и напрямую получить уведомление, или вы можете позже проверить наличие ошибки в несколькими способами .

Будьте осторожны при записи в сокет, так как может произойти SIGPIPE.В общем, вы должны установить обработчик SIGPIPE и обработать ошибку синхронно с EPIPE.

...