------------------------- EINPROGRESS(115) error EINPROGRESS The socket is nonblocking 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(2) 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). -------------------------s-kitaの日記 非ブロッキングI/OAdd Star ソケットはデフォルトでブロッキング。ソケットに関するシステムコールは、4つに分類できる。 入力操作{ read, readv, recv, recvfrom, recvmsg。これらの関数をブロッキングTCPソケットに対して 呼び出した際にソケットの受信バッファにデータが存在しない場合、 呼び出したプロセスはデータが到着するまでスリープする。 ある量のデータが到着するまで待ちたいときには、MSG_WAITALLフラグを指定する。 非ブロッキングソケットでは、入力操作が即座に終了しない場合、 これら関数呼び出しは即座にEWOULDBLOCKエラーを返して終了する。 } 出力操作{ write, writev, send, sendto, sendmsg。TCPソケットではカーネルがアプリケーションのバッファから ソケットの送信バッファにデータをコピーする。 ブロッキングソケットの送信バッファに空きがない場合、 呼び出したプロセスは秋が生じるまでスリープさせられる。 非ブロッキングTCPソケットでは、ソケットの送信バッファに空きが全くない場合、 これらの関数は、EWOULDBLOCKエラーを返して即座に終了する。 ソケットの送信バッファに空きがあった場合、カーネルがバッファにコピーできたバイト数を関数の戻り値として返す。 UDPソケットには送信バッファが存在しない。 } 新規コネクションの受付 accept関数{ 新しいコネクションが存在しないブロッキングソケットに対してacceptを呼び出すと、 呼び出したプロセスはスリープさせられる。 新しいコネクションが存在しない非ブロッキングソケットに対してacceptを呼び出すと ブロックする代わりにEWOULDBLOCKエラーが返される。 } 新規コネクションの起動 TCPに対するconnect関数{ TCPのコネクションを確立するには3WHSが必要で、connect関数はクライアントが そのSYNに対するACKを受信するまで制御を戻さない。 これはTCPに対するconnectを呼び出したプロセスは少なくとも RTT(Round Trip Time)だけブロックすることを意味する。 非ブロッキングTCPソケットに対してconnectが呼び出され、コネクションを即座に確立することが出来ない場合、 コネクションの確立が起動されるが、EINPROGRESSエラーが返される(errnoにセットされる)。 } 非ブロッキングconnect{ #include #include #include #include #include #include #include #include int set_nonblocking(int sockfd) { int val; val = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, val | O_NONBLOCK); } int set_blocking(int sockfd) { int val; val = fcntl(sockfd, F_GETFL, 0); val = val & ~(val & O_NONBLOCK); fcntl(sockfd, F_SETFL, val); } int main() { int sockfd; struct sockaddr_in server; int ret; fd_set writefds; int maxfdp1; char *req = "GET / HTTP/1.1\r\n\r\n"; int n; char buff[1024]; int len; struct timeval timeout; sockfd = socket(AF_INET, SOCK_STREAM, 0); server.sin_family = AF_INET; server.sin_port = htons(80); server.sin_addr.s_addr = inet_addr("127.0.0.1"); set_nonblocking(sockfd); ret = connect(sockfd, (struct sockaddr*)&server, sizeof(server)); set_blocking(sockfd); FD_ZERO(&writefds); FD_SET(sockfd, &writefds); maxfdp1 = sockfd + 1; timeout.tv_sec = 3; timeout.tv_usec = 0; if ( (ret = select(maxfdp1, NULL, &writefds, NULL, &timeout) ) > 0) { if (FD_ISSET(sockfd, &writefds)) { n = send(sockfd, req, strlen(req), 0); len = recv(sockfd, buff, sizeof(buff), 0); if (len > 0) { buff[len] = '\0'; printf("%s\n", buff); } } } else if (ret == 0) { printf("timeout\n"); } else { printf("error = %d\n", errno); } return 0; } } 非ブロッキングI/Oでは、ディスクリプタの読み書きの可能性を検査するために、普通selectが併用される。 -----------------------