一、多進(jìn)程服務(wù)器
-
read()
阻塞的話就是【單客戶端】響應(yīng)的服務(wù)器 - 多進(jìn)程服務(wù)器是【多客戶端響應(yīng)的服務(wù)器】
之所以需要多客戶端
響應(yīng)的原因是——
三次握手的時(shí)候是阻塞在accept()那里菜谣,然后accept()返回成功后榕订,到read()那里阻塞
這時(shí)候如果來一個(gè)新連接
况鸣,因?yàn)檫€是阻塞在read()中(一直在等待),而不在accept()中
(所以三次握手不能及時(shí)的響應(yīng)),所以【新連接請(qǐng)求】會(huì)緩存在accept隊(duì)列中
- 如果將read
和accept
都設(shè)置成非阻塞的,那么就是【非阻塞】輪詢模型牲距,這樣的壞處:每來一個(gè)客戶端鏈接,都有一個(gè)read()
钥庇,這樣后面會(huì)有越來越多的read()
(也會(huì)有越來越多的【套接字】)牍鞠。而且如果沒數(shù)據(jù)讀,會(huì)導(dǎo)致CPU空轉(zhuǎn)(CPU使用率很高)
一评姨、多進(jìn)程服務(wù)器
多進(jìn)程模型难述,在accept()和read()中間打斷,加一個(gè)fork()
吐句,fork()出來的子進(jìn)程來讀數(shù)據(jù)胁后,再關(guān)閉子進(jìn)程的fd
父進(jìn)程則是回到accept()
那里繼續(xù)監(jiān)聽,最后關(guān)閉父進(jìn)程的fd
父進(jìn)程阻塞在accept()那里嗦枢,子進(jìn)程會(huì)阻塞在read()那里攀芯,二者互相不影響,從而實(shí)現(xiàn)多進(jìn)程并發(fā)
fork()之后净宵,套接字的
引用計(jì)數(shù)
會(huì)加1敲才,但是file結(jié)構(gòu)體
沒有復(fù)制過來裹纳,只是【復(fù)制過來的指針】也指向了file結(jié)構(gòu)體,文件描述符表
復(fù)制了過來子進(jìn)程的
clntfd
和父進(jìn)程的clntfd
指向的是同一個(gè)套接字紧武,套接字的引用計(jì)數(shù)
加1
exit(-1)
退出進(jìn)程的函數(shù)
父進(jìn)程則是continue回到accept()
繼續(xù)阻塞
- pid為
-1
意味著創(chuàng)建進(jìn)程失敗
如果在連接過程中剃氧,如果客戶端先關(guān)閉,那么
客戶端的進(jìn)程
就會(huì)變成僵尸進(jìn)程
阻星,所以要處理僵尸進(jìn)程
- 如何
回收進(jìn)程
——wait()【阻塞等待】朋鞍,waitpid()【非阻塞接收】 - 多進(jìn)程服務(wù)器模型中的
accept()
和read()
是【阻塞的】,所以不能使用wait()阻塞等待
二妥箕、使用信號(hào)回收進(jìn)程
使用信號(hào)的方式回收滥酥,因?yàn)?code>父進(jìn)程一直阻塞在accept()那里等待連接,所以均不能設(shè)置成阻塞等待和非阻塞輪詢畦幢,因此使用信號(hào)
- SIGCHID(子進(jìn)程退出的時(shí)候坎吻,會(huì)給父進(jìn)程發(fā)送一個(gè)信號(hào)SIGCHID)
- sig_handler()使用
waitpid()來非阻塞的處理信號(hào)
因?yàn)榭赡苡?code>多個(gè)子進(jìn)程同時(shí)退出,所以while()來保證可以接收到所有子進(jìn)程退出的信號(hào)
三宇葱、關(guān)閉多余的fd
因?yàn)閒ork()是在accept()后面瘦真,所以fork()之前就已經(jīng)有2個(gè)fd
了——lstnfd和clntfd,但是子進(jìn)程又用不到lstnfd黍瞧,所以子進(jìn)程中需要關(guān)閉lstnfd
如果子進(jìn)程這里不關(guān)閉的話诸尽,那么因?yàn)閘stnfd對(duì)應(yīng)套接字的引用計(jì)數(shù)是2,所以父進(jìn)程要關(guān)閉2次fd
父進(jìn)程也要關(guān)閉clntfd印颤,不然子進(jìn)程的close(clntfd)并沒有真正的關(guān)掉您机,只是引用計(jì)數(shù)-1
(不關(guān)閉就意味著不釋放資源,會(huì)導(dǎo)致內(nèi)存泄露
)
如果服務(wù)器要把數(shù)據(jù)寫回去年局,那么就是在子進(jìn)程中讀完數(shù)據(jù)(
read
)后通過write(clntfd, buf)
將數(shù)據(jù)寫回去因?yàn)?code>write()是在子進(jìn)程中际看,如果寫的時(shí)候讀端關(guān)閉了,就會(huì)有一個(gè)信號(hào)
SIGPIPE(管道破裂)
發(fā)送給子進(jìn)程某宪,可以默認(rèn)不處理仿村,也可以處理
ulimit -a 可以查看總共可以創(chuàng)建的進(jìn)程數(shù)量
可以去系統(tǒng)改這個(gè)數(shù)量锐朴,也要考慮物理內(nèi)存的大小兴喂,如果物理內(nèi)存不夠,那么就會(huì)將一部分的進(jìn)程交換到交換分區(qū)中(比較慢)焚志,再需要使用的話則是從交換分區(qū)中恢復(fù)
如果不想去交換分區(qū)衣迷,則需要設(shè)置一下【粘住位】
fork()后子進(jìn)程和父進(jìn)程【接收到的數(shù)據(jù)】不一樣,所以會(huì)
重新申請(qǐng)物理內(nèi)存(內(nèi)存頁)
比如buf就是不一樣的酱酬,原則是【讀時(shí)共享壶谒,寫時(shí)復(fù)制】`