1,write原型,參數及返回值。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
------函數write 只是將用戶進程中的數據拷貝到內核緩衝區中,拷貝數據的大小取決於內核緩衝區的大小與nbytes。
參數:
fd:標示某個套接字;
buf:進程中需要往對端發送的數據;
nbytes:需要發送的數據長度。
返回值:
-1:相應的錯誤碼會寫到error中。
error :EAGAIN 或 EWOULDBLOCK,表示緩衝區已滿,此時無法寫入,需要等待下次機會。(EAGAIN和EWOULDBLOCK 兩者本質一樣,只是分別用於不同的系統,前者是gnu,即linux,後者是bsd系統,都表示緩衝區已滿,無空間可寫)
error:EPIPE,這是一種典型的錯誤場景,當client A 已經關閉了,server B 由於網絡延遲等原因未察覺,依然向這個已關閉的fd,執行write時,內核會向B 返回 EPIPE錯誤碼,併產生SIGPIPE,默認情況下,進程對該信號的動作是自動退出,所以一般服務器需要處理該信號。
>0:寫入內核緩衝區的數據大小。
=0:返回一般不會爲0,根據第3個參數的值,如果爲0,則表示啥都不執行,write返回0。
2,write 在阻塞和非阻塞下的區別。
- 阻塞下
當內核緩衝區大小不足以容納需要寫入的 nbytes,write一直阻塞等待,直到緩衝區大小 >= nbytes 時,write一次性copy,等待的過程中,有可能會被信號中斷。
當內核緩衝區大小能夠容納需要寫入的nbytes,write copy到緩衝區,並返回 nbytes。
- 非阻塞
堅持的原則是有多少寫多少,如果內核緩衝區空間足夠,同阻塞情況,一次性copy;如果緩衝區不夠,則緩衝區的大小是有多少就寫入多少,並返回該值,顯然返回值小於nbytes,此種情況需要循環的方式將nbytes數據寫到緩衝區;如果緩衝區是滿的,則返回-1,並置error值爲EAGAIN 或 EWOULDBLOCK。
3,write 的循環寫入。
int nwrite(int fd, char *buf, int nbytes)
{
int len = 0;
char *ptr = buf;
int left = nbytes;
while(left)
{
len = write(fd, ptr, left);
if(len < 0)
{
if(error == EAGAIN)
len = 0;
else
return -1; //真正的錯誤
}
if(len == 0)
{
break;
}
left -= len;
ptr += len;
}
return nbytes;
}
4,write 遺留幾個問題?
write非阻塞的時候需要檢測中斷嗎?
write一次性能最大寫入緩衝區多少字節?
5,總結
write | 阻塞下 | 非阻塞 |
緩衝區滿 | 一直等待 | 返回-1,並置error爲EAGAIN |
有緩衝區,但不夠指定寫的大小 | 一直等待,直到有足夠空間 | 寫入一部分,並返回該寫入的部分大小 |
有緩衝區,而且大小也夠 | 一次性寫入 | 一次性寫入 |