欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网络编程3(多路复用)

程序员文章站 2024-02-09 17:24:28
...

c多路复用

  使用一个进程(且只有一个主线程)同时监控若干个socket文件描述符的读写,这种读写模式叫做多路复用

  多用于TCP服务端,用于监控若干个客户端的连接和数据的收发

优点:不需要频繁地创建进程、销毁进程,从而达到节约内存资源、时间资源,也能避免进程之间的竞争、等待

缺点:单个客户端的任务不能耗时太长,否则其他客户端就会感知到。

  适合并发量高、任务量短小的情景,例如:Web服务器

select

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval* timeout);
/*
功能:监控多个文件描述符的读、写、异常操作
nfds:被监控的文件描述符中最大的+1
readfds:监控读操作的文件描述符集合
writefds:监控写操作的文件描述符集合
exceptfds:监控异常操作的文件描述符集合
timeout:设置超时时间
		NULL				一直阻塞,直到某个文件描述符发生变化
		大于0				等待超时时间,超时后返回0
		0秒0毫秒			非阻塞
返回值:监控到发生相关操作的文件描述符的个数,超时返回0,错误返回-1
*/

//fd_set 是文件描述符的集合,是要通过以下函数进行操作:
void FD_CLR(int fd, fd_set *set);
//功能:从集合中删除fd文件描述符
int  FD_ISSET(int fd, fd_set *set);
//功能:判断集合中是否存在fd文件描述符
void FD_SET(int fd, fd_set *set);
//功能:把文件描述符添加到集合中
void FD_ZERO(fd_set *set);
//功能:清空集合

注意:
  readfds、writefds、exceptfds 这三个参数即是输入也是输出,也就是说调用select时这三个集合里面需要存放着被监控的文件描述符,当函数因为监控的文件描述符发生变化而返回时,发生变化的文件描述符会存在集合中,没发生变化的就删除掉了。

select设计不合理的地方

  1、每次调用select时都需要重新向它传递被监控者的集合
  2、调用结束后若想要知道哪些文件描述符发生了相关操作,需要把所有的被监控的文件描述符都测试一遍

select的优点

  它是最早的多路复用的函数,几乎所有的操作系统都支持,程序的兼容性高

pselect

[只是select增强版,本质上没有区别,缺点没变]

#include <sys/select.h>
int pselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);
/*
功能:与select大致相同
区别:
		1、超时时间的类型不同,pselect的精度更高
		2、pselect的timeout,即是输入也是输出,可以返回剩余的时间,但是select只是输入
		3、pselect监听时可以通过sigmask参数设置要想要在监听时屏蔽的信号,可以保证pselect的监听不被信号干扰
*/

poll

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
/*
功能:
fds:pollfd的结构体数组
nfds:数组的长度
timeout:超时时间
返回值:监听到发生相关操作的描述符的个数,超时返回0,错误返回-1
*/
struct pollfd {
   int   fd;         //	被监听的文件描述符
   short events;     //	要监听的事件
   short revents;    //	实际监听到的事件
  		POLLIN					普通优先级的读事件
      POLLPRI					高优先级的读事件
      POLLOUT					普通优先级的写事件
     	POLLRDHUP				对方socket关闭
      POLLERR					错误事件
      POLLHUP					对方挂起事件
      POLLNVAL				非法描述符
};

epoll

#include <sys/epoll.h>
int epoll_create(int size);
/*
功能:创建一个epoll对象,该对象可以保存被监控的描述符
size:epoll对象能保存描述符的数量
返回值:创建成功的epoll对象
*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
/*
功能:控制epoll对象,添加、删除描述符
epfd:epoll对象的描述符,即epoll_create的返回值
op:
		EPOLL_CTL_ADD		添加socket文件描述符
		EPOLL_CTL_DEL		删除socket文件描述符
		EPOLL_CTL_MOD		修改要监控的事件
fd:
		想要操作的socket文件描述符
event:
		想要监控的事件,可以参考poll的事件
返回值:成功返回0,失败返回-1
*/
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
/*
功能:监控文件描述符,并返回产生事件的文件描述符
epfd:epoll对象的描述符,即epoll_create的返回值
events:输出型参数,用于获取产生事件的文件描述符
maxevents:可以返回的最大的事件数目
time_out:超时时间
返回值:事件发生的描述符的数量
*/

epoll的优点

  1、只需要添加一次描述符,不需要重复赋值
  2、会把发生变化的文件描述符返回,因此不需要遍历全部的文件描述符即可
  3、编程结构简洁

epoll的条件触发和边缘触发

  条件触发:当文件缓冲区中有要读取的数据时就会触发事件【像键盘】

  边缘触发:当数据发送时只触发一次事件【像鼠标】

    1、事件设置为 EPOLLET 边缘触发

    2、要循环读取缓冲区,直到缓冲区读完

    3、要以非阻塞的模式读取

    4、返回-1表示读取完毕,才能进行下一次epoll_wait

    优点:降低事件触发的次数

相关标签: c语言

上一篇: java程序设计 3 复用

下一篇: