默认情况下,系统为我们分配的套接字(文件描述符)是阻塞的,我们使用阻塞的套接字(文件描述符)执行connect、read、write、accept等函数的话,会阻塞一段系统默认的超时时间,当然这个超时时间可以通过setsockopt函数的相关参数进行设置,但不论如何都会阻塞一段这个指定的时间。如果您的程序是单线程,或者该线程需要执行多任务,一旦阻塞这就不能执行其他任务了,这并不是我们希望看到的,那么有没有办法让基于该套接字(文件描述符)的动作(如connect)立刻返回呢?答案是肯定的。
如果我们将套接字(文件描述符)设置为非阻塞模式,那么执行句居如connect这样默认阻塞的函数时,除非能够立马返回结果,否则系统会立刻令其返回一个错误值并接管该函数的最终运行结果。然会立刻返回的问题解决了,但是仍给系统以后的函数,我们如何去获得其最终执行结果呢?我们可以使用select来监控该套接字(文件描述符),让它帮我们与系统交互,以获得函数的最终执行结果。
下面就给出一个基于非阻塞套接字的connect函数实例。
#include <stdio.h>
#include <types.h>
#include <time.h>
#define SLEEP_TIME 2
#define PORT_UP 8848
#define CPPLIVE "192.168.1.100"
int main(void)
{
int error, ret;
int fd_num;
int new_fd;
int non_blocking = 1;
fd_set wtitefds;
struct timeval select_timeval;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_UP);
addr.sin_addr.s_addr = inet_addr(CPPLIVE);
if ((new_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
return -1;
}
//Set Non-blocking
if (ioctl(node->remoteFd, FIONBIO, &non_blocking) < 0)
perror("ioctl");
ret = connect(new_fd, (struct sockaddr *)&addr, sizeof(addr));
if ( 0 == ret)
{
printf("connect to %s successed!\n", CPPLIVE);
return 0;
}
if (-1 == ret && errno != EINPROGRESS)
{
perror("connect");
close(new_fd);
return -1;
}
while (1)
{
FD_ZERO(&wtitefds);
FD_SET(new_fd, &wtitefds);
fd_num = select(new_fd+1, NULL, &wtitefds, NULL, &select_timeval);
if (fd_num < 0)
{
perror("select");
continue;
}
else if (0 == fd_num)
{
printf("select timeout...\n");
//resert the select_time after timeout
select_timeval.tv_sec = SLEEP_TIME;
select_timeval.tv_usec = 0;
//you can add some task here, so the task could work a time every SLEEP_TIME
continue;
}
if (FD_ISSET(new_fd, &wtitefds))
{
printf("the connect have done\n");
if (getsockopt(new_fd, SOL_SOCKET, SO_ERROR, &error, &error_len) != 0)
{
perror("getsockopt");
return -1;
}
if (error)
{
perror("connect");
return -1;
}
else
{
printf("connect to %s successed!\n", CPPLIVE);
return 0;
}
}
}
return 0;
}
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。



