使用GNULinux系统调用`splice`在Haskell中进行零拷贝Socket到Socket数据传输

使用GNULinux系统调用`splice`在Haskell中进行零拷贝Socket到Socket数据传输,第1张

概述更新:Nemo先生的回答有助于解决问题!下面的代码包含修复程序!请参阅下面的nb False和nb True调用. 还有一个名为splice的新Haskell软件包(它具有特定于 *** 作系统的便携式实现,是最着名的套接字到套接字数据传输循环). 我有以下(Haskell)代码: #ifdef LINUX_SPLICE#include <fcntl.h>{-# LANGUAGE CPP #-}{- 更新:Nemo先生的回答有助于解决问题!下面的代码包含修复程序!请参阅下面的nb False和nb True调用.

还有一个名为splice的新Haskell软件包(它具有特定于 *** 作系统的便携式实现,是最着名的套接字到套接字数据传输循环).

我有以下(Haskell)代码:

#ifdef liNUX_SPliCE#include <fcntl.h>{-# LANGUAGE CPP #-}{-# LANGUAGE ForeignFunctionInterface #-}#endifmodule Network.socket.Splice (    Length,zerocopy,splice#ifdef liNUX_SPliCE,c_splice#endif  ) whereimport Data.Wordimport Foreign.Ptrimport Network.socketimport Control.Monadimport Control.Exceptionimport System.Posix.Typesimport System.Posix.IO#ifdef liNUX_SPliCEimport Data.Intimport Data.Bitsimport Unsafe.Coerceimport Foreign.C.Typesimport Foreign.C.Errorimport System.Posix.Internals#elseimport System.IOimport Foreign.Marshal.Alloc#endifzerocopy :: Boolzerocopy =#ifdef liNUX_SPliCE  True#else  False#endiftype Length =#ifdef liNUX_SPliCE  (#type size_t)#else  Int#endif-- | The 'splice' function pipes data from--   one socket to another in a loop.--   On linux this happens in kernel space with--   zero copying between kernel and user spaces.--   On other operating systems,a portable--   implementation utilizes a user space buffer--   allocated with 'mallocBytes'; 'hGetBufSome'--   and 'hPut' are then used to avoID repeated --   tiny allocations as would happen with 'recv'--   'sendAll' calls from the 'bytestring' package.splice :: Length -> Socket -> Socket -> IO ()splice l (MkSocket x _ _ _ _) (MkSocket y _ _ _ _) = do  let e  = error "splice ended"#ifdef liNUX_SPliCE  (r,w) <- createPipe  print ('+',r,w)  let s  = Fd x -- source  let t  = Fd y -- target  let c  = throwErrnoIfMinus1 "Network.socket.Splice.splice"  let u  = unsafeCoerce :: (#type ssize_t) -> (#type size_t)  let fs = sPliCE_F_MOVE .|. sPliCE_F_MORE  let nb v = do setNonBlockingFD x v                setNonBlockingFD y v  nb False  finally    (forever $do        b <- c $c_splice s nullPtr w nullPtr    l  fs       if b > 0         then   c_splice r nullPtr t nullPtr (u b) fs)         else   e    (do closeFd r        closeFd w        nb True        print ('-',w))#else  -- ..    #endif#ifdef liNUX_SPliCE-- SPliCE-- fcntl.h-- ssize_t splice(--   int          fd_in,--   loff_t*      off_in,--   int          fd_out,--   loff_t*      off_out,--   size_t       len,--   unsigned int flags-- );foreign import ccall "splice"  c_splice  :: Fd  -> Ptr (#type loff_t)  -> Fd  -> Ptr (#type loff_t)  -> (#type size_t)  -> Word  -> IO (#type ssize_t)sPliCE_F_MOVE :: WordsPliCE_F_MOVE = (#const "SPliCE_F_MOVE")sPliCE_F_MORE :: WordsPliCE_F_MORE = (#const "SPliCE_F_MORE")#endif

注意:上面的代码现在正常工作!由于Nemo,以下不再有效!

我用上面定义的splice调用了两个打开并连接的套接字(它们已经用于使用套接字API发送和接收调用传输最少量的握手数据或转换为句柄并与hGetline和hPut一起使用)并且我一直得到:

Network.socket.Splice.splice: resource exhausted (Resource temporarily unavailable)

在第一个c_splice调用站点:c_splice返回-1并将一些errno设置为一个读取资源耗尽的值(可能是EAGAIN)查找时资源暂时不可用.

我测试了不同长度值的调用splice:1024,8192.

解决方法 我不知道Haskell,但“资源暂时不可用”是EAGAIN.

它默认看起来像Haskell sets its sockets to non-blocking mode.因此,如果您在没有数据时尝试从一个读取数据,或者在其缓冲区已满时尝试写入一个数据,那么您将失败并使用EAGAIN.

弄清楚如何将套接字更改为阻止模式,我打赌你会解决你的问题.

[更新]

或者,在尝试读取或写入套接字之前调用select或poll.但是你仍然需要处理EAGAIN,因为有一些罕见的极端情况,其中linux选择将指示套接字已准备就绪,而实际上并非如此.

总结

以上是内存溢出为你收集整理的使用GNU / Linux系统调用`splice`在Haskell中进行零拷贝Socket到Socket数据传输全部内容,希望文章能够帮你解决使用GNU / Linux系统调用`splice`在Haskell中进行零拷贝Socket到Socket数据传输所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1047540.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存