网络编程 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
有缓冲区,但不够指定写的大小 一直等待,直到有足够空间 写入一部分,并返回该写入的部分大小
有缓冲区,而且大小也够 一次性写入 一次性写入

 

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