-
//read操作加上超时时间。
-
int read_timeout(int fd, void *buf, uint32_t count, int time)
-
{
-
if(time > 0) {
-
fd_set rSet;
-
FD_ZERO(&rSet);
-
FD_SET(fd, &rSet);
-
-
struct timeval timeout;
-
memset(&timeout, 0, sizeof(timeout));
-
timeout.tv_sec = time;
-
timeout.tv_usec = 0;
-
-
int ret;
-
while(1) {
-
ret = select(fd+1, &rSet, NULL, NULL, &timeout);
-
if(ret < 0) {
-
if(errno == EINTR) continue;
-
ERR_EXIT("select");
-
} else if(ret == 0) {
-
errno = ETIMEDOUT;
-
return -1;
-
} else {
-
break;
-
}
-
}
-
}
-
int readNum;
-
readNum = read(fd, buf, count);
-
return readNum;
-
}
-
//write超时
-
-
int write_timeout(int fd, void *buf, uint32_t count, int time)
-
{
-
if(time > 0) {
-
fd_set wSet;
-
FD_ZERO(&wSet);
-
FD_SET(fd, &wSet);
-
-
struct timeval timeout;
-
memset(&timeout, 0, sizeof(timeout));
-
timeout.tv_sec = time;
-
timeout.tv_usec = 0;
-
-
int ret;
-
while(1) {
-
ret = select(fd+1, NULL, &wSet, NULL, &timeout);
-
if(ret < 0) {
-
if(errno == EINTR) continue;
-
ERR_EXIT("select");
-
} else if(ret == 0) {
-
errno = ETIMEDOUT;
-
return -1;
-
} else {
-
break;
-
}
-
}
-
}
-
int writeNum;
-
writeNum = write(fd, buf, count);
-
return writeNum;
-
}
-
//accept超时操作
-
-
int accept_timeout(int fd, struct sockaddrin *addr, socklen_t *addrlen, int time)
-
{
-
int ret;
-
if(time > 0) {
-
fd_set rSet;
-
FD_ZERO(&rSet);
-
FD_SET(fd, &rSet);
-
-
struct timeval timeout;
-
timeout.tv_sec = time;
-
timeout.tv_usec = 0;
-
-
int selectRet;
-
do {
-
selectRet = select(fd + 1, &rSet, NULL, NULL, &timeout);
-
}while(selectRet < 0 && selectRet == EINTR);
-
if(selectRet < 0 ) {
-
return -1;
-
} else if(selectRet == 0) {
-
errno = ETIMEDOUT;
-
return -1;
-
}
-
}
-
if(addr) {
-
ret = accept(fd, (struct sockaddr *)addr, addrlen);
-
} else {
-
ret = accept(fd, NULL, NULL);
-
}
-
return ret;
-
}
-
//检测监听套接字是否可读,当监听套接字可读的时候,就认为连接队列发生了连接。
-
-
//connect
-
-
void setNonBlockMode(int fd)
-
{
-
int flags = fcntl(fd, F_GETFL);
-
if(flags < 0) {
-
ERR_EXIT("fcntl");
-
}
-
flags |= O_NONBLOCK;
-
if(fcntl(fd, F_SETFL, flags) < 0) {
-
ERR_EXIT("fcntl");
-
}
-
}
-
-
void setBlockMode(int fd)
-
{
-
int flags = fcntl(fd, F_GETFL);
-
if(flags < 0) {
-
ERR_EXIT("fcntl");
-
}
-
flags &= ~O_NONBLOCK;
-
if(fcntl(fd, F_SETFL, flags) < 0) {
-
ERR_EXIT("fcntl");
-
}
-
-
}
-
-
int connect_timeout(int sockfd, struct sockaddrin *addr, socklen_t addrlen, int time)
-
{
-
int ret = -1;
-
-
if(time > 0) {
-
setNonBlockMode(sockfd);
-
}
-
ret = connect(sockfd, (struct sockaddr*)addr, addrlen);
-
if(ret < 0 && errno == EINPROGRESS) {
-
fd_set wSet;
-
FD_ZERO(&wSet);
-
FD_SET(sockfd, &wSet);
-
-
struct timeval timeout;
-
timeout.tv_sec = time;
-
timeout.tv_usec = 0;
-
-
int selcetRet;
-
do{
-
selcetRet = select(sockfd + 1, NULL, &wSet, NULL, &timeout);
-
}while(selcetRet < 0 && errno == EINTR);
-
if(selcetRet < 0) {
-
ret = -1;
-
} else if(selcetRet == 0) {
-
ret = -1;
-
errno = ETIMEDOUT;
-
} else if(selcetRet > 0) {
-
int err;
-
socklen_t socklen = sizeof(err);
-
int sockoptRet = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen);
-
if(sockoptRet == -1) {
-
ret = -1;
-
}
-
if(err == 0) {
-
ret = 0;
-
} else {
-
errno = err;
-
ret = -1;
-
}
-
}
-
}
-
if(time > 0) {
-
setBlockMode(sockfd);
-
}
-
return ret;
-
}
1.设置fd为非阻塞模式。
2.调用connect操作,如果网络条件很好,比如本机两个socket发生连接,会发生成功返回。
3.正常情况下,connect立即返回-1并设置errno为EINPROGRESS 表示正在连接过程中。
4.使用select检测fd是否可写。 如果检测到可写也有如下两种情况:
1. connect连接成功。
2. 产生了错误,我们就需要用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen); 来判断是否发生了错误。