首先,我们知道,socket() 调用创建指定系列和指定类型的套接字。
s = socket(family, type, protocol);
socket将返回套接字句柄。套接字句柄即为文件描述符s,而一般情况下文件描述符默认都是阻塞的。为了满足某些时候的需要,我们使用fcntl函数来对其进行非阻塞的设置。
函数原型
#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函数,将文件描述符设置为非阻塞
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参数
轮询方式读取标准输入
#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;
}