欢迎光临
我们一直在努力

Linux系统编程第九弹——网络编程3

1. IO多路复用

  • 核心目的 — 提高并发的程度

1.1 多路IO

  • — I(input)O(output)  当前进程 有多处 输入和输出的操作
  • — 点对点通信

1.2服务器

if (pid > 0)

{

//父进程从键盘获得数据 —写到socket中

}else if (pid == 0)

{

//子进程从socket中读取数据 —输出到终端

}

1.3 复用

复用的是当前进程或线程,在一个进程或线程中 有多路IO要同时处理

  • 阻塞IO
  • 非阻塞IO
  • 信号驱动IO
  • IO多路复用

2. 阻塞IO:

  • scanf
  • getchar
  • fgets

3. 非阻塞IO:

3.1 特点:

  • 当去内核读取数据时,如果内核没有数据,则不阻塞等待,而是立即返回,所以,非阻塞方式如果想要获得数据,必须配合轮询操作。

while (1)
{
recvfrom(); //非阻塞,必须轮询
轮询到 读到数据
} //很耗CPU

3.2 信号驱动IO:

        设置好对SIGIO的信号处理函数,等有数据来了,内核会给进程发信号,进程收到信号后,再去做读取操作,不需要一直等,不需要轮询

3.3 使用流程:

1. 为内核发送的通知信号安装一个信号处理例程。默认情况下,这个通知信号为 SIGIO。
//signal 或 sigaction
signal(SIGIO,handler);

2.设定文件描述符的属主,
也就是当文件描述符上可执行 I/O 时会接收到通知信号的进程或进程组。通常我们让调用进程成为属主。设定属主可通过 fcntl()的 F_SETOWN 操作来完成:
//owner
fcntl(fd,F_SETOWN,pid); //设置文件描述符fd 属于 进程 pid

3.设置标志
通过设定 O_NONBLOCK 标志使能非阻塞 I/O。通过打开 O_ASYNC 标志使能信号驱动 I/O。 //使能 (使能够)这可以一个操作,因为它们都需要用到 fcntl()的 F_SETFL 操作
flags = fcntl(fd,F_GETFL); //获得当前标志
fcntl(fd,F_SETFL,flags|O_ASYNC|O_NONBLOCK);

3.4 特点:

1.异步的
2.效率高
3.问题 –只能处理一路IO

4. IO多路复用:

1.用函数 (select/epoll (poll))监控多路IO
2.如果那一路IO有数据,则对应的函数返回,告诉用户进程有就绪的IO
3.用户进程去对应的IO读取数据

4.1 select

int select( int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

功能:

  • 监控多路IO,看是否有就绪的

参数:

  • @nfds //要监控的文件描述符 最大值+1
  • @readfds //是否可读的集合
  • @writefds //是否可写的集合
  • @exceptfds //是否异常的集合
  • @timeout
    0 //时间为0 表示select是一个非阻塞
     >0 //时间> 0 表示select阻塞对应的一段时间
    NULL //NULL 表示默认使用 阻塞方式

返回值: 表示 就绪的文件描述符的数量

  • 失败 -1&&错误码会被设置

void FD_CLR(int fd, fd_set *set); //从set中清除fd
int FD_ISSET(int fd, fd_set *set); //判断fd是否在set中
void FD_SET(int fd, fd_set *set); //将fd添加到set中
void FD_ZERO(fd_set *set); //将set清0

select使用流程:

1.准备监控文件描述符 表
fd_set readfds;
FD_ZERO(&readfds);

2.添加要监控的文件描述符
FD_SET(fd,&readfds);
FD_SET(0,&readfds);

3.准备 nfsd
nfds = fd + 1;

4.调用select函数
select(nfds,&readfds,NULL,NULL,NULL);

注意:

1. select函数调用完之后,会将监控结果的文件描述符集合带回给readfds
select监控到就绪的文件描述符后,会将未就绪的清零

2. select 监控 超时时,
select 函数 每次 会将 timeout中的时间往下减,减的结果放到timeout中
使用时timeout中值,每次调用前,需要重新给值。

4.2 epoll

1.创建监控的epoll对象 epoll_create

① int epoll_create(int size);
功能:

  • 创建epoll对象,返回文件描述符

参数:

  • @size 并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。

返回值:

  • 成功 是epoll描述符。
  • 失败 -1表示创建失败。

2.epoll_ctl 函数

② int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:

  • epoll对象的控制函数

参数:

  • @epfd —epoll对象
  • @op
    epoll_ctl控制对指定描述符fd执行op操作,event是与fd关联的监听事件。
    op操作有三种:
    添加EPOLL_CTL_ADD,
    删除EPOLL_CTL_DEL,
    修改EPOLL_CTL_MOD。
    分别添加、删除和修改对fd的监听事件。
  • @fd 就是要操作的fd
  • @event —事件的结构体

typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events —epoll事件 */
epoll_data_t data; /* User data variable — 用户的数据 */
};
event 这个参数中 —要存放 关心的事件 及 对应fd
EPOLLIN 可读
EPOLLOUT 可写
EPOLLERR 异常条件
EPOLLET 边沿触发模式,
在描述符状态跳变时才上报监听事件。(监听默认都是LT模式)
返回值:

  • 返回0表示控制成功,返回-1表示失败。

③ int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:

  • 监控文件描述符是否就绪

参数:

  • @epfd — 表示 监控的epoll对象
  • @events — 表示 获得就绪事件的一个结构体指针 (理解为一个struct epoll_event 类型的数组名)
  • @maxevents — 表示 该数组的最大长度
  • @timeout — 表示超时的时间,单位 毫秒
    timeout — 0 //非阻塞
    timeout — -1 //阻塞
    timeout — 非负数 //表示阻塞 多少 微秒

返回值:

  • 成功 返回就绪的文件描述符数量
    设置了超时,超时时间到了,没有就绪的,则返回0
  • 失败 -1 && errno
赞(0)
未经允许不得转载:171主机测评 » Linux系统编程第九弹——网络编程3
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址