使用socket編程實現(xiàn)數(shù)據(jù)傳輸?shù)倪^程中,通常的默認(rèn)設(shè)置假設(shè)套接字是阻塞的。每個TCP套接字有一個發(fā)送緩沖區(qū)典勇,當(dāng)應(yīng)用進程調(diào)用write操作的時候,內(nèi)核從應(yīng)用進程的緩沖區(qū)中復(fù)制數(shù)據(jù)到套接字的發(fā)送緩沖區(qū)中叮趴。
如果套接字的發(fā)送緩沖區(qū)無法完全的容納應(yīng)用的應(yīng)用程序所發(fā)送的數(shù)據(jù)割笙,即應(yīng)用程序的緩沖區(qū)大于套接字發(fā)送緩沖區(qū)或套接字緩沖區(qū)還有其他數(shù)據(jù),應(yīng)用進程將會被掛起并疫向。內(nèi)核將不從write系統(tǒng)條用返回咳蔚,直到應(yīng)用進程緩沖區(qū)中的所有數(shù)據(jù)都復(fù)制到套接字發(fā)送緩沖區(qū)豪嚎。
所以搔驼,從寫一個tcp套接字的write調(diào)用成功返回僅僅表示可以重新使用應(yīng)用進程的緩沖區(qū),并不表示對端的應(yīng)用進程已經(jīng)接收到了數(shù)據(jù)侈询。
下面是發(fā)送和接收兩個方面說明“阻塞”和“非阻塞”模式的區(qū)別:
(1)發(fā)送操作:write 舌涨、writev、send扔字、sendto囊嘉、sendmsg
對于tcp套接字,內(nèi)核將從應(yīng)用進程的緩沖區(qū)向該套接字的的發(fā)送緩沖區(qū)復(fù)制數(shù)據(jù)革为。對于阻塞的套接字扭粱,如果其發(fā)送緩沖區(qū)中沒有空間,進程將掛起震檩,直到有空間為止琢蛤。
對于一個非阻塞的tcp套接字蜓堕,如果其發(fā)送緩沖區(qū)中根本就沒有空間,發(fā)送函數(shù)調(diào)用將立即返回一個EWOULDBLOCK錯誤博其。如果其緩沖區(qū)中有一些空間套才,返回值將是內(nèi)核能夠復(fù)制到該緩沖區(qū)中的字節(jié)數(shù)。
對于UDP套接字慕淡,不存在真正的發(fā)送緩沖區(qū)背伴。內(nèi)核只是復(fù)制應(yīng)用進程數(shù)據(jù)并把它沿協(xié)議棧向下傳送,一次加上UDP頭部和IP頭部峰髓。因此傻寂,對一個阻塞的UDP套接字,發(fā)送函數(shù)調(diào)用將不會因為與TCP套接字一樣的原因而阻塞携兵,不過有可能會因為其他原因而阻塞崎逃。
(2)接受操作 read readv recv recvfrom recvmsg
如果某個進程對一個阻塞的TCP套接字調(diào)用這些輸入函數(shù)之一,而該套接字的接受緩沖區(qū)沒有數(shù)據(jù)可以讀眉孩,該進程將被掛起个绍,直到到達一些數(shù)據(jù)。tcp是字節(jié)流協(xié)議浪汪,只要到達一些數(shù)據(jù)巴柿,該進程就會被喚醒,這些數(shù)據(jù)既可能是單個字節(jié)死遭,也可以是一個完整的TCP分節(jié)中的數(shù)據(jù)广恢。
UDP是數(shù)據(jù)包協(xié)議,如果一個阻塞的UDP套接字的接受緩沖區(qū)為空呀潭,對它調(diào)用接收函數(shù)的進程將被掛起钉迷,直到到達一個UDP數(shù)據(jù)報。
對于非阻塞的套接字钠署,如果接收操作不能被滿足(對于UDP套接字即有一個完整的數(shù)據(jù)報可讀)糠聪,相應(yīng)的調(diào)用將立即返回一個EWOULDBLOCK錯誤。