这篇博客就是在成熟的nws框架下面, epoll采用边缘ET方式, 用send简单改写一下sendfile64,算是熟悉一下流程。 epoll的ET方式只有在写缓冲由满到不满或者读缓冲区由空到非空时候才触发,所以我们每次利用send发送数据一定要填满内核发送缓冲区,才可以触发下一次epoll事件。
这是需要改写的sendfile函数 : n = sendfile64(ofd, ifd, (off64_t*)&offset64, count); 我呢只把这些参数传递到我改写的函数里面,直接利用就行,这些值都是nws框架给我的,肯定也是正确的。ifd是我要从磁盘读文件的fd, ofd是我要发送的fd, offset64是发送的偏移量, count是我要发送的长度。我改写的函数代码如下:
// vaynedu_test_code
#define BUF_SIZE_VAYNEDU (512 * 1024)
int sendfile_aio_test(int ofd, int ifd, off64_t *offset64, size_t count)
{
int pre ad_num;
int send_num = 0;
int send_len = 0;
int num = 0;
size_t len = count >= BUF_SIZE_VAYNEDU ? BUF_SIZE_VAYNEDU : count;
char *buf = (char *)malloc(len);
char *p = buf;
memset(buf, 0, len);
pread_num = pread(ifd, buf, len , *offset64);
if(pread_num < 0){
printf("pread failed : %d\n", pread_num);
return -1;
}else if(pread_num == 0){
printf("pread finished\n");
}
while(pread_num > 0){
send_len = pread_num > 8192? 8192 : pread_num;
num = send(ofd, p, send_len, 0);
send_num += num;
if(num >= 0 && num < send_len ){
printf("num = %d\n", num);
break;
}else if(num < 0){
if(errno == EAGAIN){
printf("%s\n", strerror(errno));
continue;
}
break;
}
pread_num -= num;
p += send_len;
}
printf("ifd = %d, len = %lu, offset64 = %llu, pread_num = %d, send_num = %d\n\n", ifd, len, *offset64, pread_num, send_num);
free(buf);
buf = NULL;
return send_num;
}
我先根据count值,来确定开辟buf的大小。根据传入偏移量的值用pread读出数据存入buf。 pread_num是从磁盘读取成功的字节数。剩下的就是用send发送了。 send这里要根据返回值num做出下一步决定。 如果num = 8912字节, 那我就继续用send发送,一直等到num= 0 或者num < 8192,这就证明发送缓冲区已经别填满了,不要在发送了,用send_num记录发送的总字节数。 可能会遇到EAGAIN的情况,这也就是缓冲区满了,再试一次。