我们怎么实现非阻塞io
函数fcntl
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
传入的cmd的值不同, 后面追加的参数也不相同.
fcntl函数有5种功能:
复制一个现有的描述符(cmd=F_DUPFD).
获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW
实现函数SetNoBlock
void SetNoBlock(int fd) {
int fl = fcntl(fd, F_GETFL);
if (fl < 0) {
perror("fcntl");
return;
}
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}
具体得代码 makefile
testNonBlock: main.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -rf testNonBlock
util.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <cerrno>
void setNonBlock(int fd)
{
std::cout<<111<<std::endl;
int f1 = fcntl(fd, F_GETFL);
if (f1 < 0)
{
std::cout << "fcntl" << errno << strerror(errno) << std::endl;
}
fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}
void printLog()
{
std::cout << "this is a log" << std::endl;
}
void download()
{
std::cout << "this is a download" << std::endl;
}
void executeSql()
{
std::cout << "this is a executeSql" << std::endl;
}
main.cc
#include "util.hpp"
#include <cstdio>
#include <vector>
#include <functional>
#include <sys/select.h>
using namespace std;
using func_t = function<void()>;
void init(vector<func_t> &cbs)
{
cbs.push_back(printLog);
cbs.push_back(download);
cbs.push_back(executeSql);
}
void doWork(const vector<func_t> &cbs)
{
for (auto const &cb : cbs)
{
cb();
}
}
int main()
{
vector<func_t> cbs;
init(cbs);
setNonBlock(0);
char buffer[1024];
while (true)
{
// printf(">>> ");
// fflush(stdout);
ssize_t n = read(0, buffer, sizeof(buffer) - 1);
if (n > 0)
{
// 我们在终端输入得时候输入为 111\n 若我们buffer[n]=0 结果 111\n\0 会多输出一个空格
buffer[n - 1] = 0;
cout << "echo# " << buffer << std::endl;
}
else if (n == 0)
{
cout << "read end" << endl;
break;
}
else
{ // -1
// 11Resource temporarily unavailable
// cout << n << endl;
// cout << errno << strerror(errno) << endl;
if(errno==EAGAIN)
{
cout<<"我没错 ,我只是没有数据"<<endl;
doWork(cbs);
}
else if(errno==EINTR)
{
continue;
}
else
{
std::cout << "n : " << n << " errno: " << strerror(errno) << std::endl;
break;
}
}
sleep(1);
}
return 0;
}
我们先要知道这里是怎么运行得 ,当我们不输入得时候 ,会执行else得分支。
这里得n =-1 errno=11 Resource temporarily unavailable
这里单纯得n=-1不能辨别非阻塞式IO 。要通过对错误码得观察。
这里得错误码为11 Resource temporarily unavailable 资源未到达在这里并不是一种错误,这时候我们就需要对这个错误码进判别 ,可以去做其他得任务。这里假设我们 得任务很长 ,我们还能及时得响应吗?我验证一下。
执行完一个得时候,我们sleep 3 秒
void doWork(const vector<func_t> &cbs)
{
for (auto const &cb : cbs)
{
cb();
sleep(3);
}
}
结果:是能马上处理的(太厉害了)
[zk@VM-24-17-centos lesson42]$ ./testNonBlock
111
我没错 ,我只是没有数据
this is a log
this is a download
this is a executeSql
asdasd
echo# asdasd
我没错 ,我只是没有数据
this is a log
this is a download
这里还有一个
else if(errno==EINTR)
{
continue;
}```
这种被系统中断也不是异常得