網絡編程 write 阻塞和非阻塞下的區別

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
有緩衝區,但不夠指定寫的大小 一直等待,直到有足夠空間 寫入一部分,並返回該寫入的部分大小
有緩衝區,而且大小也夠 一次性寫入 一次性寫入

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章