當(dāng)使用非阻塞(connect)時(shí),可能會(huì)返回錯(cuò)誤碼EINPROGRESS,表示連接正在進(jìn)行中。這是因?yàn)榉亲枞B接是異步的,它會(huì)立即返回并在后臺(tái)進(jìn)行連接操作。為了解決這個(gè)問(wèn)題,你可以使用以下方法之一:
使用select或epoll等多路復(fù)用技術(shù),等待連接完成。這樣你可以在連接完成后再繼續(xù)進(jìn)行后續(xù)操作。
使用非阻塞IO時(shí),可以使用poll或epoll等函數(shù)來(lái)檢查連接是否已經(jīng)建立。你可以通過(guò)檢查套接字的可寫(xiě)事件來(lái)判斷連接是否已經(jīng)建立。
使用非阻塞IO時(shí),可以使用非阻塞的connect函數(shù),它會(huì)立即返回,但是需要不斷地使用poll或epoll等函數(shù)來(lái)檢查連接狀態(tài),直到連接完成。
下面是一個(gè)使用非阻塞connect的示例代碼:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
int connect_nonblock(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int timeout) {
int flags, ret;
fd_set rset, wset;
struct timeval tv;
// 設(shè)置套接字為非阻塞模式
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
// 發(fā)起非阻塞連接
ret = connect(sockfd, addr, addrlen);
if (ret == 0) {
// 連接成功,恢復(fù)套接字阻塞模式
fcntl(sockfd, F_SETFL, flags);
return ret;
} else if (ret < 0 && errno != EINPROGRESS) {
// 連接出錯(cuò)
return ret;
}
// 使用select等待連接完成
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
tv.tv_sec = timeout;
tv.tv_usec = 0;
ret = select(sockfd + 1, &rset, &wset, NULL, &tv);
if (ret <= 0) {
// 連接超時(shí)或出錯(cuò)
return ret;
}
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
// 連接完成,恢復(fù)套接字阻塞模式
fcntl(sockfd, F_SETFL, flags);
return ret;
}
// 連接超時(shí)
errno = ETIMEDOUT;
return -1;
}
int main() {
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(80);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
if (connect_nonblock(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr), 5) < 0) {
perror("connect_nonblock");
return -1;
}
// 連接完成,進(jìn)行后續(xù)操作
// ...
close(sockfd);
return 0;
}
這個(gè)示例代碼使用了select函數(shù)來(lái)等待連接完成,可以根據(jù)自己的需求選擇使用其他多路復(fù)用技術(shù)來(lái)替代select。在connect_nonblock函數(shù)中,首先將套接字設(shè)置為非阻塞模式,然后發(fā)起非阻塞連接。如果連接成功,恢復(fù)套接字阻塞模式并返回。如果連接出錯(cuò),直接返回錯(cuò)誤碼。如果連接未完成,則使用select等待連接完成,并在連接完成后恢復(fù)套接字阻塞模式并返回。如果連接超時(shí),則返回錯(cuò)誤碼ETIMEDOUT。