UNIX网络编程笔记(6):I/O复用之select函数
上一講中我們正確處理了僵尸子進(jìn)程,使得這個(gè)簡(jiǎn)單的服務(wù)器更加健壯。不幸的是,這個(gè)程序仍然有問(wèn)題。想象一下,如果一個(gè)客戶正在和一個(gè)服務(wù)器子進(jìn)程連接建立完畢正在通話,而服務(wù)器子進(jìn)程意外終止(比如kill),服務(wù)器TCP向客戶TCP發(fā)送一個(gè)FIN,但客戶端正在調(diào)用fgets函數(shù)等待用戶輸入字符而得不到這個(gè)FIN,直到套接字讀為止(可能過(guò)了很長(zhǎng)時(shí)間)。
1、來(lái)看看問(wèn)題是什么
首先啟動(dòng)服務(wù)器與客戶,建立連接:
客戶輸入nihao后服務(wù)器正確回射,然后kill掉服務(wù)器子進(jìn)程后客戶輸入and...,輸出錯(cuò)誤:
服務(wù)器端重啟(上一講中解決的問(wèn)題)。
這個(gè)過(guò)程發(fā)生了什么?
(1)當(dāng)kill掉服務(wù)器子進(jìn)程后,服務(wù)器父進(jìn)程正確處理了SIGCHLD信號(hào)。服務(wù)器也向客戶發(fā)送一個(gè)FIN,客戶回應(yīng)一個(gè)ACK,TCP連接終止的前半部分完成;
(2)客戶上沒有發(fā)生任何特殊的事,客戶TCP接收到服務(wù)器的FIN后回應(yīng)一個(gè)ACK,但問(wèn)題是客戶正阻塞在fgets上,等待用戶輸入;
(3)在客戶上再輸入and...,導(dǎo)致錯(cuò)誤發(fā)生:str_cli調(diào)用write,客戶TCP接著把數(shù)據(jù)發(fā)送給服務(wù)器,但是客戶FIN的接收并沒有告知客戶TCP服務(wù)器進(jìn)程已經(jīng)終止。當(dāng)服務(wù)器TCP接收到客戶的數(shù)據(jù)時(shí),發(fā)送一個(gè)RST;
(4)但是客戶進(jìn)程看不到這個(gè)RST,因?yàn)檎{(diào)用write后直接調(diào)用readline,并且由于之前接收的FIN,導(dǎo)致readline直接返回0(表示EOF)。但客戶沒有預(yù)期收到EOF,于是出錯(cuò);
(5)客戶終止,所有打開的描述符關(guān)閉;
問(wèn)題的根本在于,當(dāng)FIN到達(dá)套接字時(shí),客戶正阻塞在fgets調(diào)用上。客戶實(shí)際上在應(yīng)對(duì)兩個(gè)描述符:套接字和用戶輸入,它不能單純阻塞在某個(gè)特定的源上。select函數(shù)可以解決這個(gè)問(wèn)題。
2、select函數(shù)
有些進(jìn)程需要一種預(yù)先告知內(nèi)核的能力,使得內(nèi)核一旦發(fā)現(xiàn)進(jìn)程指定的一個(gè)或多個(gè)I/O條件就緒時(shí),它就通知進(jìn)程。這個(gè)能力就是I/O復(fù)用。
select函數(shù)允許進(jìn)程指示內(nèi)核等待多個(gè)事件中的任何一個(gè)發(fā)生,并只在有一個(gè)或多個(gè)事件發(fā)生或經(jīng)歷一段指定的時(shí)間后才喚醒它。
下面的例子指出select可以告知內(nèi)核在什么條件下發(fā)生時(shí)返回:
- 集合{1,4,5}中的任何描述符準(zhǔn)備好讀;
- 集合{2,7}中的任何描述符準(zhǔn)備好寫;
- 集合{1,4}中的任何描述符由異常條件待處理;
- 已經(jīng)過(guò)了12.8秒;
(2)服務(wù)器端:
可以看到,程序運(yùn)行良好。
總結(jié)
以上是生活随笔為你收集整理的UNIX网络编程笔记(6):I/O复用之select函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: sharpaquos如何设置电视?
- 下一篇: UNIX网络编程笔记(7):回射程序的U