本文共 2360 字,大约阅读时间需要 7 分钟。
既然我们已经有了系统提供的接口read和write,为什么还需要readn writen 和readline呢?
因为字节流套接字上调用read或write输入和输出的字节数可能比请求的数量少,然而这不是出错状态(在我的另一篇博文: 已经指出),为了预防万一,不让实现返回一个不足的字节计数值,unix网络编程作者就封装了以下函数
在/unpv13e/lib 下unp.h中有如下申明
ssize_t readn(int, void *, size_t);ssize_t writen(int, const void *, size_t);
在lib/下 vim readn.c
/* include readn */#include "unp.h"ssize_t /* Read "n" bytes from a descriptor. */readn(int fd, void *vptr, size_t n){ size_t nleft; ssize_t nread; char *ptr; //我们人工的加了一层缓冲区,用于存read从fd处读到的指定字节 ptr = vptr; nleft = n; while (nleft > 0) {//下面操作刚接触网络编程的人可能不太理解,read默认是阻塞函数,也就是说应用进程可能会阻塞到此处(如资源数据还没准备到位),对于阻塞函数,我们需要仔细分析每一种//返回值情况,从而一一处理,read返回值的三种状态,正整数,0,,1,以后我会专门以源码出发的角度详解) if ( (nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) /*表示此调用被信号中断*/ nread = 0; /* and call read() again */ else return(-1); /*错误发生,返回-1,文件读写位置无法预期,只能返回-1(表示错误)退出 */ } else if (nread == 0) /*读到文件尾部或者对端执行关闭操作*/ break; /* EOF */ nleft -= nread; ptr += nread; } return(n - nleft); /* return >= 0 */}/* end readn *//*包裹函数*/ssize_tReadn(int fd, void *ptr, size_t nbytes){ ssize_t n; if ( (n = readn(fd, ptr, nbytes)) < 0) err_sys("readn error"); return(n);}//readn函数:从一个描述符读n字节
在lib/ 下 vim writen.c /* include writen */#include "unp.h"ssize_t /* Write "n" bytes to a descriptor. */writen(int fd, const void *vptr, size_t n){ size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) //被信号中断 nwritten = 0; /* and call write() again */ else return(-1); /* error ,文件读写位置无法预期*/ } nleft -= nwritten; ptr += nwritten; } return(n);}/* end writen *//*包裹函数*/voidWriten(int fd, void *ptr, size_t nbytes){ if (writen(fd, ptr, nbytes) != nbytes) err_sys("writen error");}
转载地址:http://qjumi.baihongyu.com/