Güncelleme: Bay Nemo'nun cevabı sorunun çözülmesine yardımcı oldu! Aşağıdaki kod düzeltmeyi içerir! Aşağıdaki nb False
ve nb True
çağrılarına bakın.GNU/Linux sistem çağrısını kullanarak sıfır kopyalı soket için 'splice' çağrısı Soket'e veri aktarımı Soket'e veri aktarımı
da (veri aktarımı soket en iyi bilinen soketin OS özgü ve taşınabilir uygulamaları halkaya)splice
adlı yeni bir Haskell paket bulunmaktadır.
aşağıdaki (Haskell) kodu vardır:
#ifdef LINUX_SPLICE
#include <fcntl.h>
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
#endif
module Network.Socket.Splice (
Length
, zeroCopy
, splice
#ifdef LINUX_SPLICE
, c_splice
#endif
) where
import Data.Word
import Foreign.Ptr
import Network.Socket
import Control.Monad
import Control.Exception
import System.Posix.Types
import System.Posix.IO
#ifdef LINUX_SPLICE
import Data.Int
import Data.Bits
import Unsafe.Coerce
import Foreign.C.Types
import Foreign.C.Error
import System.Posix.Internals
#else
import System.IO
import Foreign.Marshal.Alloc
#endif
zeroCopy :: Bool
zeroCopy =
#ifdef LINUX_SPLICE
True
#else
False
#endif
type 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 ('-',r,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 :: Word
sPLICE_F_MOVE = (#const "SPLICE_F_MOVE")
sPLICE_F_MORE :: Word
sPLICE_F_MORE = (#const "SPLICE_F_MORE")
#endif
Not: şimdi yukarıdakod sadece çalışıyor! Aşağıda Nemo! (Daha önce yuva API send
ve recv
çağrı kullanarak el sıkışma veri az miktarda iletimi için kullanılan ya da kolları dönüştürülür ve hGetLine
ve hPut
kullanılır) iki açık ve bağlı soketleri ile yukarıda tanımlandığı gibi splice
çağrı
ve ilk c_splice
çağrı sitesinde
Network.Socket.Splice.splice: resource exhausted (Resource temporarily unavailable)
: Ben almaya devam c_splice
getiriler -1
ve wh resource exhausted | resource temporarily unavailable
okuyan bir değere (muhtemelen EAGAIN
) bazı errno
setleri en yukarı baktı.
Farklı Length
değerleriyle splice
numaralı telefonu aramayı denedim: 1024
, 8192
.
Geçerli sürümünüz, splice() öğesini her aradığınızda yeni bir boru oluşturur. Her zaman büyük blokları hareket ettirirseniz, ancak büyük bir yüke maruz kalabilecek küçük bloklar için bu tamamdır. Genellikle, borunun sahibi olmak için bir "Splicer" nesnesi oluşturur, sonra verileri taşımak için + ile tanımlayıcıları tekrar tekrar çağırır. – Nemo
@Nemo 'splice' (' c_splice' değil) aslında sonsuza dek sonsuz bir döngüdür. Kesinleştirmek için 'splice'ı' loopSplice 'gibi bir şeye yeniden adlandırmalıyım. Yani şu anda her bir 'c_splice' çağrısı başına değil vekil başına bir boru oluşturur. –
Windows üzerinde taşınabilir uygulama ile test etmek için hala çok şey var, bu yüzden kesinlikle daha iyi bir isim üzerinde düşünmek için yeterli zamana sahip olacağım. Önerileriniz için de açık :) –