由于read、readv、write和writev函数一次读或写有时并不能满足所要求的数据,因此需要多次调用直到要求的字节数或者出错。针对这4个系统调用,编写了对应的xxxn版本,实现如下
1/**********************************************************************************************************
2 In the following four functions,the optional parameter tran indicate the number of bytes read or written,or -1 if an error occurred.
3 On success,return true indicate all data had been read or written successfully,otherwise in other cases,return false indicate error or partial success.
4**********************************************************************************************************/
5
6bool readn(int fd,void* buf,size_t cnt,ssize_t* tran/**//*=NULL*/)
7{
8 size_t left = cnt;
9 ssize_t ret;
10 char* ptr = (char*)buf;
11
12 while(left > 0){
13 ret = read(fd,ptr,left);
14 if(ret > 0){
15 left -= ret;
16 ptr += ret;
17 }else if(0==ret || left != cnt)
18 break;
19 else{
20 if(tran) *tran = -1;
21 return false;
22 }
23 }
24 if(tran) *tran = cnt-left;
25 return 0==left;
26}
27
28bool writen(int fd,const void* buf,size_t cnt,ssize_t* tran/**//*=NULL*/)
29{
30 size_t left = cnt;
31 ssize_t ret;
32 char* ptr = (char*)buf;
33
34 while(left > 0){
35 ret = write(fd,ptr,left);
36 if(ret > 0){
37 left -= ret;
38 ptr += ret;
39 }else if(0==ret || left != cnt)
40 break;
41 else
42 if(tran) *tran = -1;
43 return false;
44 }
45 if(tran) *tran = cnt-left;
46 return 0==left;
47}
48
49static int get_iov_tran_index(const struct iovec* iov,int iovcnt,size_t trans,size_t& tran)
50{
51 size_t cnt = 0; int i;
52
53 for(i=0;i < iovcnt;++i){
54 cnt += iov[i].iov_len;
55 if(trans < cnt){
56 tran = iov[i].iov_len - (cnt - tran);
57 break;
58 }
59 }
60 return i;
61}
62
63bool readvn(int fd,const struct iovec* iov,int iovcnt,ssize_t* tran/**//*=NULL*/)
64{
65 if(iovcnt > IOV_MAX){
66 if(tran) *tran = -1;
67 errno = EINVAL;
68 return false;
69 }
70 size_t all_cnt = 0,all_tran = 0,one_tran;
71 ssize_t ret;
72
73 struct iovec _iov[IOV_MAX];
74 int i;
75 for(i=0;i < iovcnt;++i){
76 _iov[i] = iov[i];
77 all_cnt += iov[i].iov_len;
78 }
79
80 i = 0;
81 do{
82 ret = readv(fd,&_iov[i],iovcnt-i);
83 if(ret > 0){
84 all_tran += ret;
85 if(all_tran==all_cnt)
86 break;
87
88 i = get_iov_tran_index(iov,iovcnt,all_tran,one_tran);
89 assert(i < iovcnt);
90 _iov[i].iov_base = iov[i].iov_base + one_tran;
91 _iov[i].iov_len = iov[i].iov_len - one_tran;
92
93 }else if(0==ret)
94 break;
95 else{
96 if(tran) *tran = -1;
97 return false;
98 }
99 }while(all_tran < all_cnt);
100
101 if(tran) *tran = all_tran;
102 return all_tran==all_cnt;
103}
104
105bool writevn(int fd,const struct iovec* iov,int iovcnt,ssize_t* tran/**//*=NULL*/)
106{
107 if(iovcnt > IOV_MAX){
108 if(tran) *tran = -1;
109 errno = EINVAL;
110 return false;
111 }
112 size_t all_cnt = 0,all_tran = 0,one_tran;
113 ssize_t ret;
114
115 struct iovec _iov[IOV_MAX];
116 int i;
117 for(i=0;i < iovcnt;++i){
118 _iov[i] = iov[i];
119 all_cnt += iov[i].iov_len;
120 }
121
122 i = 0;
123 do{
124 ret = writev(fd,&_iov[i],iovcnt-i);
125 if(ret > 0){
126 all_tran += ret;
127 if(all_tran==all_cnt)
128 break;
129
130 i = get_iov_tran_index(iov,iovcnt,all_tran,one_tran);
131 assert(i < iovcnt);
132 _iov[i].iov_base = iov[i].iov_base + one_tran;
133 _iov[i].iov_len = iov[i].iov_len - one_tran;
134
135 }else if(0==ret)
136 break;
137 else{
138 if(tran) *tran = -1;
139 return false;
140 }
141 }while(all_tran < all_cnt);
142
143 if(tran) *tran = all_tran;
144 return all_tran==all_cnt;
145} 从以上代码可看出,readvn和writevn的实现并不是循环对每一个缓冲区简单地调用readn或writen,而是多次调用原生的readv或writev,因为对于读写多个缓冲区,使用readv或writev的效率通常要比多次调用read或write高,所以这样做就会尽可能减少系统调用的次数,提高效率。
posted on 2013-08-02 19:44
春秋十二月 阅读(1745)
评论(0) 编辑 收藏 引用 所属分类:
System