还有一个名为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数据传输所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)