非阻塞IO

首先,我们知道,socket() 调用创建指定系列和指定类型的套接字。

s = socket(family, type, protocol);

socket将返回套接字句柄。套接字句柄即为文件描述符s,而一般情况下文件描述符默认都是阻塞的。为了满足某些时候的需要,我们使用fcntl函数来对其进行非阻塞的设置。

函数原型

1
2
3
4
#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd,int cmd,.../*arg*/);

传入的cmd的值不同,后面追加的参数也不相同。

fctnl函数有五种功能:

  • 复制一个现有的文件描述符(cmd = F_DUPFD)
  • 获得/设置文件描述符标记(cmd = FGETFD或FSETFD)
  • 获得/设置文件状态标记(cmd = FGETFL或FSETFL)
  • 获得/设置异步I/O所有权(cmd = FGETOWN 或 FSETOWN)
  • 获得/设置记录锁(cmd = FGETLK,FSETLK或F_SETLKW)

我们此处只是用第三种功能,获得/设置文件状态标记,就可以将一个文件描述符设置为非阻塞。

实现函数SetNoBlock

基于fcntl,我们实现一个SetNoBlock函数,将文件描述符设置为非阻塞

1
2
3
4
5
6
7
8
9
10
11
void SetNoBlock(int fd)
{
int f1 = fcntl(fd,F_GETFL);

if(f1 < 0){
perror("fcntl");
return;
}

fcntl(fd,F_SETFL,f1 | O_NONBLOCK);
}
  • 使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图)
  • 然后再使用FSETFL将文件描述符设置回去。设置回去的同时,加上一个O_NONBLOCK参数

轮询方式读取标准输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void SetNoBlock(int fd)
{
int f1 = fcntl(fd,F_GETFL);
if(f1 < 0){
perror("fcntl");
return;
}
fcntl(fd,F_SETFL,f1 | O_NONBLOCK);
}

int main()
{
SetNoBlock(0);
while(1){
char buf[1024] = {0};
ssize_t read_size = read(0,buf,sizeof(buf)-1);
if(read_size < 0){
perror("read");
slepp(1);
continue;
}
printf("input :%s\n",buf);
}
return 0;
}
0%