數(shù)據(jù)的IO和復(fù)用
網(wǎng)絡(luò)數(shù)據(jù)能夠正常的到達(dá)用戶膝昆,并被用戶接受網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)哪康耐璞摺>W(wǎng)絡(luò)數(shù)據(jù)的接受以及發(fā)送有多種方案,例如直接接受或者發(fā)送數(shù)據(jù)通過(guò)向量發(fā)送接受數(shù)據(jù)荚孵,通過(guò)消息進(jìn)行接受以及發(fā)送妹窖。
1.介紹主要的常用的IO函數(shù)
2。介紹幾種常用的IO模型
3 介紹select和pselect函數(shù)收叶,如何利用這兩個(gè)文件的描述符號(hào)進(jìn)行文件讀寫(xiě)描述符的監(jiān)視骄呼。
4.簡(jiǎn)單的介紹函數(shù)poll和ppoll含義使用以及區(qū)別
5 以簡(jiǎn)單的例子介紹非堵塞編程。
--------------------------------------------------? ? ?IO 函數(shù)? ? -----------------------------------------------
recv函數(shù)用于接受數(shù)據(jù),函數(shù)的原型如下蜓萄。recv函數(shù)從套接字s中接受數(shù)據(jù)放到緩沖區(qū)buf中隅茎,buf的長(zhǎng)度為len,操作的方式由flag決定嫉沽。第一個(gè)參數(shù)s是套接字文件的描述符辟犀,它是由函數(shù)socket()返回的,第二個(gè)參數(shù)buf是一個(gè)指針绸硕,指向接受網(wǎng)絡(luò)套接字的緩沖區(qū)堂竟,第三個(gè)參數(shù)表示緩沖區(qū)的大小,以字節(jié)為單位臣咖。
#include <sys/type.h>
#include <sys/socket.h>
ssize_t recv(int s,void * buf,size_t len,int flags);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?flags的值以及含義
MSG_DONTWAIT? ? ? ? ? ? ? ? ? ? 非阻賽的操作跃捣,立刻返回不等待
MSG_ERRQUEUE? ? ? ? ? ? ? ? ? ?錯(cuò)誤消息從套接字錯(cuò)誤隊(duì)列接收
MSG_OOB? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 接收外數(shù)據(jù)數(shù)據(jù)
MSG_PEEK? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?查看數(shù)據(jù),不進(jìn)行數(shù)據(jù)緩沖區(qū)的清空
MSG_TRUNC? ? ? ? ? ? ? ? ? ? ? ? ? ? ?返回所有的數(shù)據(jù)夺蛇,及時(shí)指定緩沖區(qū)過(guò)小
MSG_WAITALL? ? ? ? ? ? ? ? ? ? ? ? ? 等待所有的消息
MSG_DONTWAIT:這個(gè)標(biāo)志將單個(gè)IO操作設(shè)為非堵塞方式疚漆,而不需要在套接字上打開(kāi)非堵塞的標(biāo)志,執(zhí)行IO操作刁赦。然后關(guān)閉非堵塞的標(biāo)志娶聘。
MSG_ERRQUEUE:? 改錯(cuò)誤的傳輸依賴于所使用的協(xié)議。
MSG_OOB :這個(gè)標(biāo)志可以接收帶外數(shù)據(jù)甚脉,而不接收一般的數(shù)據(jù)丸升。
MSG_PEEK : 這個(gè)標(biāo)志用于查看可讀數(shù)據(jù),在recv函數(shù)執(zhí)行后牺氨,內(nèi)核不會(huì)將這些數(shù)據(jù)丟棄掉狡耻。
MSG_TRUNC: 在接收數(shù)據(jù)后,如果用戶的緩沖區(qū)大小不足以完全復(fù)制緩沖區(qū)的數(shù)據(jù)猴凹,則將數(shù)據(jù)折斷夷狰,僅復(fù)制用戶緩沖區(qū)大小的數(shù)據(jù),多余的數(shù)據(jù)將會(huì)舍棄掉郊霎。
MSG_WAITALL:這個(gè)標(biāo)志告訴內(nèi)核在沒(méi)有讀到請(qǐng)求的字節(jié)數(shù)之前不使讀操作返回沼头。如果系統(tǒng)支持使用這個(gè)標(biāo)志,可以去掉readn()函數(shù)而使用下面的代替
#define readn(fd,ptr,n) recv(fd,ptr,n,MSG_WAITALL)
即使設(shè)置MSG_WAITALL书劝,如果發(fā)生以下情況(a)捕獲一個(gè)信號(hào)(b)連接終止(c)在套接字上發(fā)生了錯(cuò)誤进倍,這個(gè)函數(shù)返回的字節(jié)數(shù)依然會(huì)比請(qǐng)求的少。當(dāng)指定MSG_WAITALL標(biāo)志時(shí)购对,函數(shù)會(huì)復(fù)制與用戶指定長(zhǎng)度相等的數(shù)據(jù)猾昆。如果內(nèi)核中的當(dāng)前數(shù)據(jù)不能滿足要求,會(huì)一直等待直到數(shù)據(jù)足夠才返回骡苞。
函數(shù)recv()的返回值是成功接收到的字節(jié)數(shù)垂蜗。當(dāng)返回-1時(shí)錯(cuò)誤發(fā)生坑赡,可以查看errno獲取錯(cuò)誤碼,當(dāng)另一個(gè)訪民啊使用close()關(guān)閉連接時(shí)么抗,返回值為0;
常見(jiàn)的錯(cuò)誤碼如下:
EAGAIN? ? ? ? ? 套接字定義為非堵塞亚铁,而操作采用了堵塞的方式蝇刀,或者定義的超時(shí)時(shí)間已經(jīng)達(dá)到卻沒(méi)有接收到數(shù)據(jù)。
EBADF? ?參數(shù)s不是合法的描述符
ECONNREFUSED? 遠(yuǎn)程主機(jī)不允許此操作
EFAULT? 接受緩沖區(qū)指針在此進(jìn)程之外
EINTR? ? ? 接收到中斷信號(hào)
EINTVAl? ?傳遞了不合法的參數(shù)
ENOTCONN? ?套接字s表示流式套接字徘溢,此套接字沒(méi)有連接吞琐。
ENOTSOCK? ?參數(shù)不是套接字描述符
recv()函數(shù)通常用于TCP類(lèi)型的套接字。UDP使用recvfrom()函數(shù)接受數(shù)據(jù)然爆,當(dāng)然在數(shù)據(jù)包套接字綁定地址一節(jié)端口號(hào)后站粟,也可以使用recv()接受數(shù)據(jù)。
recv()函數(shù) 從內(nèi)核的接收緩沖區(qū)復(fù)制到數(shù)據(jù)到用戶指定的緩沖區(qū)曾雕。當(dāng)內(nèi)核的緩沖區(qū)比指定的緩沖區(qū)小時(shí)奴烙,一般情況下(沒(méi)有采用MSG_WAITALL標(biāo)志)會(huì)復(fù)制緩沖區(qū)的所有的數(shù)據(jù)到用戶緩存區(qū)。并返回?cái)?shù)據(jù)的長(zhǎng)度剖张。當(dāng)內(nèi)核的接收的緩沖區(qū)的數(shù)據(jù)比用戶指定的多時(shí)切诀,會(huì)將用戶指定長(zhǎng)度的len的接收緩沖區(qū)的數(shù)據(jù)復(fù)制到用戶指定地址。其余的數(shù)據(jù)需要下次調(diào)用該函數(shù)時(shí)在復(fù)制搔弄,內(nèi)核在復(fù)制用戶指定的數(shù)據(jù)之后幅虑,會(huì)銷(xiāo)毀已經(jīng)復(fù)制完畢的數(shù)據(jù),并進(jìn)行調(diào)整顾犹。
使用send()函數(shù)發(fā)送數(shù)據(jù)
send()函數(shù)用于發(fā)送數(shù)據(jù)倒庵,函數(shù)的原型如下
#include<sys/types.h>
#include <sys/socket.h>
ssize_t send(int s,const void * buf,size_t len,int flags)
send()函數(shù)將緩沖區(qū)buf大小為len的數(shù)據(jù)。通過(guò)套接字文件描述符按照f(shuō)lags指定的方式發(fā)送出去炫刷,其中的參數(shù)含義與recv中的含義一致擎宝,它的返回值是成功的字節(jié)數(shù),用于用戶的緩沖區(qū)buf中的數(shù)據(jù)在通過(guò)send()函數(shù)進(jìn)行發(fā)送的時(shí)候柬唯,并不一定能夠全部發(fā)送出去认臊,所以要檢查send() 函數(shù)的返回值,按照與計(jì)劃發(fā)送的字節(jié)長(zhǎng)度是否相等來(lái)判斷下一步的操作锄奢。
當(dāng)send()函數(shù)的返回值小于len的時(shí)候失晴,表明緩沖區(qū)仍然由部分?jǐn)?shù)據(jù)沒(méi)有成功的發(fā)送,這時(shí)需要重新發(fā)送剩余的部分拘央,通常剩余數(shù)據(jù)發(fā)送的方法是對(duì)原來(lái)的buf中的數(shù)據(jù)位置進(jìn)行偏移涂屁,偏移的大小為已經(jīng)成功發(fā)送的字節(jié)數(shù)。
send 函數(shù)錯(cuò)誤嗎如下:
函數(shù)send()只能用于套接字處于連接狀態(tài)的描述符灰伟,之前必須使用connect()函數(shù)或者其它函數(shù)進(jìn)行連接拆又。對(duì)于send()函數(shù)和write()函數(shù)之間的差別表示發(fā)送方式的flag儒旬,當(dāng)flag為0時(shí),send()函數(shù)和write()函數(shù)完全一致帖族,而且send(s,buf,len,flags)與sendto(s,buf,len,flags,NULL,0)等價(jià)的栈源。