Вызвав 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() работает иначе.
Кто-нибудь может попробовать запустить на иных ОС?