与TCP循环服务器模型类型,一次只能处理一个客户端
不同之处在于不会出现一个客户端独占服务器的情况(2)UDP并发服务器模型
人们把并发的概念用于UDP就得到了UDP并发服务器模型。
UDP并发服务器模型TCP服务器模型一样,创建一个子进程来处理客户端的请求
除非UDP服务器在处理某个客户端的请求时所用的时间比较长,人们实际上较少用这种模型。close(sockfd);的作用可以用 close-on-exec实现
四、I/O模型 Linux上的文本操作不同模型的效率 在UNIX/Linux下主要有5种I/O 模型 针对单个设备: 阻塞IO模型 非阻塞IO模型 信号驱动IO模型 异步IO模型 针对多个设备: IO多路复用模型 数据从内核准备好再转移到用户态的过程,一般分为两个阶段,(父进程里int sockfd = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); )
- 第一个是等待io就绪,
- 第二个是数据在内核空间和用户空间之间的移动。
close-on-exec以下( 因为socket灭有没有文件状态标志设置接口 ) 每个文件描述符都有一个close-on-exec标志。默认情况下,这个标志最后一位被设置为 0。这个标志符的具体作用在于当开辟其他进程调用exec()族函数时,在调用exec函数之前为exec族函数释放对应的文件描述符fcntl(sockfd, F_SETOWN, getpid());
父子进程中的端口占用情况。父进程监听一个端口后,fork出一个子进程,然后kill掉父进程,再重启父进程,这个时候提示端口占用,用netstat查看,子进程占用了父进程监听的端口。
原理其实很简单,子进程在fork出来的时候,使用了写时复制(COW,Copy-On-Write)方式获得父进程的数据空间、 堆和栈副本,这其中也包括文件描述符。刚刚fork成功时,父子进程中相同的文件描述符指向系统文件表中的同一项(这也意味着他们共享同一文件偏移量)。这其中当然也包含父进程创建的socket。
接着,一般我们会调用exec执行另一个程序,此时会用全新的程序替换子进程的正文,数据,堆和栈等。此时保存文件描述符的变量当然也不存在了,我们就无法关闭无用的文件描述符了。所以通常我们会fork子进程后在子进程中直接执行close关掉无用的文件描述符,然后再执行exec。
但是在复杂系统中,有时我们fork子进程时已经不知道打开了多少个文件描述符(包括socket句柄等),这此时进行逐一清理确实有很大难度。我们期望的是能在fork子进程前打开某个文件句柄时就指定好:“这个句柄我在fork子进程后执行exec时就关闭”。其实时有这样的方法的:即所谓 的 close-on-exec。
回到我们的应用场景中来,只要我们在创建socket的时候加上 SOCK_CLOEXEC 标志,就能够达到我们要求的效果,在fork子进程中执行exec的时候,会清理掉父进程创建的socket。
int sockfd = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
也可以用fcntl来修改文件状态标志
fcntl(fd, F_SETFD, 1) 此句将fd的close-on-exec 标志设置为1,开启 SOCK_CLOEXEC
fcntl(fd, F_SETFD, 0) 此句将fd的close-on-exec 标志设置为0,关闭 SOCK_CLOEXEC
需要在父进程就开启,只子进程开启的话,只能在孙进程生效了socket非阻塞模式的实现: fd = open("filename", O_RDWR | O_CREAT | O_TRUNC | O_NONBLOCK, 0666); sockfd = socket (没有文件状态标志设置接口) fcntl 操作(文件设置),管理文件描述符 setsockopt (套接字设置) #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ );
- fd : 需要操作的文件描述符
- cmd : 操作文件描述的指令
- arg : 可变参
int flag;
flag = fcntl(sockfd, F_GETFL); (返回值就是获取的文件状态标志)step 2:将O_NONBLOCK标志( 非阻塞标识)加入到文件状态标志
flag = flag | O_NONBLOCK;step 3:重新设置文件状态标志(F_SETFL, 设置文件状态标志)
fcntl(sockfd, F_SETFL, flag); (通过第三个参数flag来制定需要设置的文件状态标志)------------------------------------------------------------------------------------------------------------------------------------- (3)信号驱动IO模型(SIGIO) 第一个阶段:非阻塞异步方式等待IO就绪 第二个阶段:用户自己调用系统调用搬运数据 优点:改进了第一个阶段,是第一个阶段变成异步的 缺点:没有改进第二个阶段 因为进程-----内核,都参与工作,才实现了异步 信号驱动IO实现: step 1:设置SIGIO信号的信号处理函数 signal(SIGIO, signalhanler); step 2:设置接受SIGIO信号的进程 fcntl ( F_SETOWN ,设置接受SIGIO信号的进程标志) fcntl(sockfd, F_SETOWN, getpid()); ( 根据第三个参数制定进程号) step 3:产生SIGIO信号 O_ASYNC( 开启信号驱动IO模型) int flag; flag = fcntl(sockfd, F_GETFL); ( 返回值就是获取的文件状态标志)(F_GETFL,获取文件状态标志) flag = flag | O_ASYNC; ( 将O_ASYNC标志加入到文件状态标志) fcntl(sockfd, F_SETFL, flag); ( 通过第三个参数flag来制定需要设置的文件状态标志(F_SETFL, 设置文件状态标志)) ------------------------------------------------------------------------------------------------------------------------------------- (4)异步io模型 ------------------------------------------------------------------------------------------------------------------------------------- (5)多路复用IO模型 调用的函数是: 实现: 加1指最多文件描述个数 timeout <select.h>
标签:标志,文件,UDP,exec,模型,IO,进程 来源: https://blog.csdn.net/xavier679/article/details/80878755
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。