write函數首先將進程需要發送的數據先放在進程緩沖區中,然后向socket的發送緩沖區進行拷貝,在此,可能出現這樣情況,即當進程緩沖區中的數據量大於此時發送緩沖區中所能接受的數據量時,若此時處於阻塞模式,應用進程將會被掛起,直到進程緩沖區中的數據全部拷貝到發送緩沖區中,注意此時內核也不會返回write函數,因此,在阻塞模式下,若write函數正常返回,這也並不代表數據已經完成被對方進程接收,至多只能說明數據已經被發送緩沖區完全接受;若是處於非阻塞模式,此時write操作將會失敗,內核會立即返回EAGAIN錯誤,在此需要聲明的是,有時候在某些地方說會返回EWOULDBLOCK錯誤,其實二者本質一樣,只是分別用於不同的系統罷了,前者主要是出現於GNU系統,,而后者主要出現在類BSD系統。 www.2cto.com
【引申1】阻塞與非阻塞的轉換:切換socket fd的阻塞標志。
int fcntl(int fd , int cmd)
int fcntl(int fd,int cmd,long arg)
其中cmd代表要操作的命令,常見有:
F_GETFL:取得fd的當前狀態標志
F_SETFL:設置fd的當前狀態標志
[cpp]
flags = (long) fcntl(pc->fd, F_GETFL);
bflags = flags & ~O_NONBLOCK; /* clear non-block flag, i.e. block */
fcntl(pc->fd, F_SETFL, bflags);
【引申2】
Linux中發送緩存大小的查看:
sysctl -a | grep net.ipv4.tcp_wmem
net.ipv4.tcp_wmem = 4096 16384 81920 (這三個值分別代表發送緩沖區的最少字節數,默認字節數以及最多字節數) www.2cto.com
2. write常見錯誤以及原因分析:
前面已經說過EAGAIN錯誤出現的原因,下面主要講解EPIPE錯誤是在何種情景下產生的。
我們知道TCP連接需要三次握手,而退出需要四個過程,而EPIPE則是產生於進程socket的退出過程中,對應上面的原理圖,若B端的進程已經主動關閉(發送FIN),但是A端因為各種原因(主要是未同步),未能知曉並仍然向對方發送數據,此時A端內核會返回EPIPE錯誤,它會發送SIGPIPE信號給進程A,默認情況下,進程將會自動退出。
最近在做項目過程中,因為Apache server端的keep-alive配置時間過短,導致過早發出FIN,而使得client端的socket出現EPIPE錯誤,最后將keep-alive時間配置稍長點,一切問題OK