美文网首页
多进程服务器

多进程服务器

作者: StevenHD | 来源:发表于2020-12-24 23:45 被阅读0次

一、多进程服务器

  • read()阻塞的话就是【单客户端】响应的服务器
  • 多进程服务器是【多客户端响应的服务器】

之所以需要多客户端响应的原因是——

三次握手的时候是阻塞在accept()那里,然后accept()返回成功后,到read()那里阻塞

这时候如果来一个新连接,因为还是阻塞在read()中(一直在等待),而不在accept()中(所以三次握手不能及时的响应),所以【新连接请求】会缓存在accept队列中

- 如果将readaccept都设置成非阻塞的,那么就是【非阻塞】轮询模型,这样的坏处:每来一个客户端链接,都有一个read(),这样后面会有越来越多的read()(也会有越来越多的【套接字】)。而且如果没数据读,会导致CPU空转(CPU使用率很高)

一、多进程服务器

多进程模型,在accept()和read()中间打断,加一个fork(),fork()出来的子进程来读数据,再关闭子进程的fd

父进程则是回到accept()那里继续监听,最后关闭父进程的fd

父进程阻塞在accept()那里,子进程会阻塞在read()那里,二者互相不影响,从而实现多进程并发

  • fork()之后,套接字的引用计数会加1,但是file结构体没有复制过来,只是【复制过来的指针】也指向了file结构体,文件描述符表复制了过来

  • 子进程的clntfd和父进程的clntfd指向的是同一个套接字,套接字的引用计数加1

exit(-1)退出进程的函数
父进程则是continue回到accept()继续阻塞

  • pid为-1意味着创建进程失败

如果在连接过程中,如果客户端先关闭,那么客户端的进程就会变成僵尸进程,所以要处理僵尸进程

  • 如何回收进程——wait()【阻塞等待】,waitpid()【非阻塞接收】
  • 多进程服务器模型中的accept()read()是【阻塞的】,所以不能使用wait()阻塞等待

二、使用信号回收进程

使用信号的方式回收,因为父进程一直阻塞在accept()那里等待连接,所以均不能设置成阻塞等待和非阻塞轮询,因此使用信号

  • SIGCHID(子进程退出的时候,会给父进程发送一个信号SIGCHID)
  • sig_handler()使用waitpid()来非阻塞的处理信号

因为可能有多个子进程同时退出,所以while()来保证可以接收到所有子进程退出的信号

三、关闭多余的fd

因为fork()是在accept()后面,所以fork()之前就已经有2个fd了——lstnfd和clntfd,但是子进程又用不到lstnfd,所以子进程中需要关闭lstnfd

如果子进程这里不关闭的话,那么因为lstnfd对应套接字的引用计数是2,所以父进程要关闭2次fd

父进程也要关闭clntfd,不然子进程的close(clntfd)并没有真正的关掉,只是引用计数-1(不关闭就意味着不释放资源,会导致内存泄露

  • 如果服务器要把数据写回去,那么就是在子进程中读完数据(read)后通过write(clntfd, buf)将数据写回去

  • 因为write()是在子进程中,如果写的时候读端关闭了,就会有一个信号SIGPIPE(管道破裂)发送给子进程,可以默认不处理,也可以处理

ulimit -a 可以查看总共可以创建的进程数量

  • 可以去系统改这个数量,也要考虑物理内存的大小,如果物理内存不够,那么就会将一部分的进程交换到交换分区中(比较慢),再需要使用的话则是从交换分区中恢复

  • 如果不想去交换分区,则需要设置一下【粘住位】

fork()后子进程和父进程【接收到的数据】不一样,所以会重新申请物理内存(内存页)比如buf就是不一样的,原则是【读时共享,写时复制】`

相关文章

网友评论

      本文标题:多进程服务器

      本文链接:https://www.haomeiwen.com/subject/emidnktx.html