read函数_readn、writen和readline函数分析

字节流套接字上的read和write函数所表现的行为不同于通常的文件IO。字节流套接字上调用read和write输入或输出的字节数可能比请求的数量少,因为内核中用于套接字的缓冲区是有限制的,需要调用者多次调用read或write函数。

提示:readn、writen和readline是对read和wirte的封装。

readn(int fd,void *vptr, size_t n)

从描述符fd中读取n个字节,存入vptr指针的位置。思路如下:

  1. 当剩余长度大于0的时候就一直读啊读
  2. 当read的返回值小于0的时候,做异常检测
  3. 当read的返回值等于0的时候,退出循环
  4. 当read的返回值大于0的时候,拿剩余长度减read的返回值,拿到新的剩余长度,读的入口指针加上read的返回值,进入步骤1
  5. 返回参数n减去剩余长度,即实际读取的总长度
/* 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;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;		/* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;				/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(n - nleft);		/* return >= 0 */
}
/* end readn */

ssize_t
Readn(int fd, void *ptr, size_t nbytes)
{
	ssize_t		n;

	if ( (n = readn(fd, ptr, nbytes)) < 0)
		err_sys("readn error");
	return(n);
}

writen(int fd,const void* vptr, size_t n)

像描述符fd中写入n个字节,从vptr位置开始写。思路如下:

  1. 当要写入的剩余长度大于0的时候就一直写啊写
  2. 当write的返回值小于0的时候,做异常检测
  3. 当write的返回值等于0的时候,出错退出程序
  4. 当write的返回值大于0的时候,拿剩余长度减去write的返回值,拿到新的剩余长度,写的入口指针加上write的返回值,进入步骤1
  5. 返回参数n的值,即期望写入的总长度
/* 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 */

void
Writen(int fd, void *ptr, size_t nbytes)
{
	if (writen(fd, ptr, nbytes) != nbytes)
		err_sys("writen error");
}

readline(int fd,void *vptr, size_t maxlen)

从描述符fd中读一行文本,长度不超过maxlen,一次读1个字节。思路如下:

  1. 当读取的次数小于maxlen的时候就一直读啊读
  2. 当read的返回值等于1的时候,将读到的值赋值给ptr++,判断是不是n
  3. 当read的返回值等于0的时候,读完了
  4. 当read的返回值小于0的时候,做异常检测
  5. 进入步骤1
  6. 返回实际读取的长度
/* include readline */
#include	"unp.h"
/* PAINFULLY SLOW VERSION -- example only */
/*        痛苦 慢速版 -- 仅供示例         */
ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t	n, rc;
	char	c, *ptr;

	ptr = vptr;
	for (n = 1; n < maxlen; n++) {
        again:
		if ( (rc = read(fd, &c, 1)) == 1) {
			*ptr++ = c;
			if (c == 'n')
				break;	/* newline is stored, like fgets() */
		} else if (rc == 0) {
			*ptr = 0;
			return(n - 1);	/* EOF, n - 1 bytes were read */
		} else {
			if (errno == EINTR)
				goto again;
			return(-1);		/* error, errno set by read() */
		}
	}

	*ptr = 0;	/* null terminate like fgets() */
	return(n);
}
/* end readline */

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
	ssize_t		n;

	if ( (n = readline(fd, ptr, maxlen)) < 0)
		err_sys("readline error");
	return(n);
}

readline(int fd,void *vptr, size_t maxlen)

my_read(int fd,char *ptr) 替换 read(fd,&c,1),实现一个较快速版本。思路如下:

  1. 当读取的次数小于maxlen的时候就一直读啊读
  2. 进入my_read函数,这个函数每次最多读MAXLINE个字符,然后每次返回一个字符
  3. 将读到的值赋值给ptr++,判断是不是n
  4. 当read的返回值等于0的时候,读完了
  5. 当read的返回值小于0的时候,做异常检测
  6. 进入步骤1
  7. 返回实际读取的长度
/* include readline */
#include	"unp.h"

static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static ssize_t
my_read(int fd, char *ptr)
{
	if (read_cnt <= 0) {
        again:
		if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
			if (errno == EINTR)
				goto again;
			return(-1);
		} else if (read_cnt == 0)
			return(0);
		read_ptr = read_buf;
	}

	read_cnt--;
	*ptr = *read_ptr++;
	return(1);
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t	n, rc;
	char	c, *ptr;

	ptr = vptr;
	for (n = 1; n < maxlen; n++) {
		if ( (rc = my_read(fd, &c)) == 1) {
			*ptr++ = c;
			if (c == 'n')
				break;	/* newline is stored, like fgets() */
		} else if (rc == 0) {
			*ptr = 0;
			return(n - 1);	/* EOF, n - 1 bytes were read */
		} else
			return(-1);		/* error, errno set by read() */
	}

	*ptr = 0;	/* null terminate like fgets() */
	return(n);
}

ssize_t
readlinebuf(void **vptrptr)
{
	if (read_cnt)
		*vptrptr = read_ptr;
	return(read_cnt);
}
/* end readline */

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
	ssize_t		n;

	if ( (n = readline(fd, ptr, maxlen)) < 0)
		err_sys("readline error");
	return(n);
}

参考文献:《UNIX网络编程 卷1:套接字联网API》

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值