找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3842|回复: 3

修改ACE自带的模拟sendfile()实现

[复制链接]
发表于 2009-11-10 14:51:09 | 显示全部楼层 |阅读模式
ace/OS_NS_sys_sendfile.cpp中sendfile_emulation的实现有些问题,unix系统ACE_OS::mmap的offset参数必须是内存页面大小的整数倍,否则会出错。虽然常用的是0,但有时用到非0值的时候就要注意了。

简单修改了下。(假设内存页大小为4k)


在windows上可以用TransmitFile()来模拟。具体实现相当tricky,详细说明见代码注释。

  1. // $Id: OS_NS_sys_sendfile.cpp 84216 2009-01-22 18:34:40Z johnnyw $
  2. #include "ace/OS_NS_sys_sendfile.h"
  3. #include "ace/OS_NS_sys_mman.h"
  4. #include "ace/OS_NS_unistd.h"
  5. #if defined (ACE_WIN32) || defined (HPUX)
  6. # include "ace/OS_NS_sys_socket.h"
  7. #else
  8. # include "ace/OS_NS_unistd.h"
  9. #endif  /* ACE_WIN32 || HPUX */
  10. #ifndef ACE_HAS_INLINED_OSCALLS
  11. # include "ace/OS_NS_sys_sendfile.inl"
  12. #endif  /* ACE_HAS_INLINED_OSCALLS */
  13. ACE_BEGIN_VERSIONED_NAMESPACE_DECL
  14. #if defined ACE_HAS_SENDFILE && ACE_HAS_SENDFILE == 0
  15. ssize_t
  16. ACE_OS::sendfile_emulation (ACE_HANDLE out_fd,
  17.                        ACE_HANDLE in_fd,
  18.                        off_t * offset,
  19.                        size_t count)
  20. {
  21.      // @@ Is it possible to inline a call to ::TransmitFile() on
  22.      //    MS Windows instead of emulating here?
  23.      // @@ We may want set up a signal lease (or oplock) if supported by
  24.      //    the platform so that we don't get a bus error if the mmap()ed
  25.      //    file is truncated.
  26. #if defined (ACE_WIN32)
  27.      // 0表示取系统默认值,也可自定义大小
  28.      static const size_t BytesPerSend = 0;
  29.      if (offset != NULL)
  30.          ACE_OS::lseek(in_fd, (ACE_OFF_T)offset, SEEK_SET);
  31.      // 记录发送前文件指针位置
  32.      ACE_OFF_T currentOffset = ACE_OS::lseek(in_fd, 0, SEEK_CUR);
  33.      // 当前文件指针+count不得超过文件尾,否则TransmitFile出错WSAEINVAL。
  34.      // 此时需修改count
  35.      ACE_OFF_T eofPosition = ACE_OS::lseek(in_fd, 0, SEEK_END);
  36.      ACE_OS::lseek(in_fd, currentOffset, SEEK_SET);
  37.      size_t bytesLeft = (size_t)(eofPosition - currentOffset);
  38.      if (bytesLeft < count)
  39.          count = bytesLeft;
  40.      // 发送从当前文件指针开始的count个字节的数据
  41.      // count==0表示传送从当前文件指针到文件尾的所有数据
  42.      BOOL suc = ::TransmitFile((SOCKET)out_fd, in_fd, count, BytesPerSend, 0, 0, TF_USE_DEFAULT_WORKER);
  43.      if (suc == FALSE)  
  44.          return -1;
  45.      // TransmitFile()的文件指针自动设置不可依赖(仅在第一次调用时前进BytesPerSend,
  46.      // 而不是实际发送值count,而且以后再次调用时不再前进)。需要自己控制绝对值
  47.      currentOffset += count;
  48.      ACE_OS::lseek(in_fd, currentOffset, SEEK_SET);
  49.      return count;
  50. #endif
  51.      const size_t alignmentGranularity = 4 * 1024; // page size on unix
  52.      off_t adjustedOffset = (*offset / (alignmentGranularity)) * alignmentGranularity;
  53.      void * const buf =
  54.          ACE_OS::mmap (0, count, PROT_READ, MAP_SHARED, in_fd, adjustedOffset);
  55.      if (buf == MAP_FAILED)
  56.          return -1;
  57.      size_t memoryOffset = *offset % (alignmentGranularity);
  58.      void* readPtr = (char*)buf + memoryOffset;
  59.      size_t countLeft = count - memoryOffset;
  60. #if defined (HPUX)
  61.      ssize_t const r =
  62.          ACE_OS::send (out_fd, static_cast<const char *> (readPtr), countLeft);
  63. #else
  64.      ssize_t const r = ACE_OS::write (out_fd, readPtr, countLeft);
  65. #endif /* HPUX */
  66.      (void) ACE_OS::munmap (buf, count);
  67.      if (r > 0)
  68.          *offset += static_cast<off_t> (r);
  69.      return r;
  70. }
  71. #endif  /* ACE_HAS_SENDFILE==0 */
  72. ACE_END_VERSIONED_NAMESPACE_DECL
复制代码


[ 本帖最后由 wishel 于 2009-11-10 14:53 编辑 ]
发表于 2009-11-10 17:34:10 | 显示全部楼层
你完全可以提交patch给开发组的。
 楼主| 发表于 2009-11-11 15:58:46 | 显示全部楼层
原帖由 winston 于 2009-11-10 17:34 发表
你完全可以提交patch给开发组的。

我也是这么想,不过要把中文注释翻译成英文比较累哈哈。
再继续测一段时间吧,没问题的话就提交。
 楼主| 发表于 2009-11-12 20:19:20 | 显示全部楼层
遇到新难题:

Sendfile有个重要语义TransimitFile难以模拟:
当作用nonblock socket时,sendfile发送部分请求量(填满socket 发送缓冲)后返回发送量。
但TransimitFile却会block,一直到请求的发送量全部发送完毕才返回。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-23 13:48 , Processed in 0.360930 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表