編輯:寫在不同的線程的插座(在Haskell併發UDP服務器)
我寫在Haskell的UDP BitTorrent的追蹤。狀態是基於我的數據類型ServerState傳遞到runUDPServer,acceptConnections,的handleConnection和handleRequestData STM(二的TVar地圖)。客戶將要求開始「連接」,宣佈或刮擦。每次有人向服務器發送消息時,他們都應該收到消息。 (協議在這裏:http://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html)。
我會做一些二進制解析,IO monad中的一些處理(只是STM真的),並將二進制編碼的消息發送回發件人。最初,我想我可以在自己的線程中像這樣運行每個請求,但我想我可以分叉幾個線程,讓他們完成工作。其中一個問題可能是,整個服務器(所有線程)都會被n個發送UDP包的人阻止(但實際上這可能不是這樣)。
我想我可以更清楚地定義我的問題:如果我只是fork了所有同時運行handleConnection的線程,那麼是否會以某種方式與套接字混淆?另外,我怎麼能理想地爲每個接收到的數據包產生一個新的線程?
我的意思是,當我分叉幾個線程並寫入標準輸出時,輸出將混亂在從單獨線程打印的內容之間。 Network.accept實際上提供了一個句柄,而個別線程並不需要知道套接字,但我不能使用接受。 我不會僅僅假設從多個線程同時寫入套接字是安全的。
{-# LANGUAGE OverloadedStrings #-}
import Control.Exception (bracket)
import qualified Data.ByteString.Char8 as BS
import qualified Network.Socket as S hiding (send, sendTo, recv, recvFrom)
import qualified Network.Socket.ByteString as S
runUDPServer serverState port =
S.withSocketsDo $ bracket (createSocket port) S.close (acceptConnections serverState)
where
createSocket port = do
serverAddr <- fmap head $ S.getAddrInfo
(Just (S.defaultHints {S.addrFlags = [S.AI_PASSIVE]}))
Nothing
(Just port)
socket <- S.socket (S.addrFamily serverAddr) S.Datagram S.defaultProtocol
S.bind socket $ S.addrAddress serverAddr
return socket
acceptConnections serverState socket = do
handleConnection serverState socket
acceptConnections socket
handleConnection serverState socket = do
(requestData, remoteAddress) <- S.recvFrom socket 2048
responseData <- handleRequestData serverState requestData remoteAddress
S.sendTo socket responseData remoteAddress
handleRequestData :: ServerState -> BS.ByteString -> S.SockAddr -> IO BS.ByteString
handleRequestData serverState requestData remoteAddress = do
putStrLn "-----"
putStrLn $ "Received UDP message"
putStrLn $ "Address: " ++ show remoteAddress
-- (left out code here)
return "Dummy ByteString"
我將是任何提示非常感謝,指針等
「我寧願沒有一個線程池,每個都運行recvFrom,但我想我可以。我不知道如何以合理的方式從多線程寫入套接字。」爲什麼不?這一切都應該是在POSIX原子,對不對?如果是這樣,你可以'replicateM n(forkIO $ forever $ handleConnection socket)'。我不知道是否會對UDP套接字上的爭用造成性能影響。如果是這樣,那麼讓一個線程讀取數據並將其轉換爲阻塞的FIFO隊列可能會更快。 – jberryman
@jberryman您可以改爲動態創建線程,而不是一組線程,每個連接一個線程。 – PyRulez
此問題未包含足夠的信息以獲得完整答案。例如,你想收集所有客戶提供的信息嗎?你需要通過客戶收集它們嗎?你是否確認你目前的方法不夠快/「併發」? UDP是否適合您的用例? – Zeta