前言
网络编程中socket默认都是阻塞模式,在一些高并发或者多线程任务中,阻塞模式会极大影响效率,以connect为例,如果连接网络有问题,或者服务端不能及时响应连接,导致connect函数阻塞(阻塞时间75s),为避免这种情况,在connect前,将socket fd设置为非阻塞,然后将fd交给select监听,当fd状态发生变化,使用getsoktopt判断fd是何种类型,进而判断connect状态。
一、代码
代码如下(示例):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <errno.h>
int main()
{
int ret =0;
unsigned long ul = 1;
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
int sock = socket(AF_INET, SOCK_STREAM, 0);
ioctl(sock,FIONBIO, &ul);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("172.0.0.1");
serv_addr.sin_port = htons(8700);
fd_set sfd;
FD_ZERO(&sfd);
FD_SET(sock, &sfd);
ret = connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (ret == 0)
{
close(sock);
return 0;
}
else if (ret == -1)
{
if (errno != EINPROGRESS)
{
close(sock);
return -1;
}
int count = select(sock+1, NULL, &sfd, NULL, &timeout);
if (count == 0 || count == -1)
{
close(sock);
return -1;
}
if (FD_ISSET(sock, &sfd))
{
int err = 0;
socklen_t len = sizeof(err);
if (getsockopt(sock,SOL_SOCKET, SO_ERROR, &err, &len) == -1)
{
close(sock);
return -1;
}
if (err !=0)
{
close(sock);
return -1;
}
ul = 0;
ioctl(sock,FIONBIO, &ul);
}
}
else
{
close(sock);
return -1;
}
char buffer[10] = {0};
read(sock, buffer, sizeof(buffer)-1);
printf("resv : %s\n", buffer);
close(sock);
}