为了了解Haskell中的网络通信如何工作,我正在实现类似回波的简单UDP服务器。它应该在本地主机(端口7331)上通过IPv6侦听,接收消息并将它们回显给与另一个字符串连接的发件人。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Network.Socket hiding (send, sendTo, recv, recvFrom)
import Network.Socket.ByteString
import Control.Concurrent
import Control.Exception
import Control.Monad (forever)
import System.IO (
IOMode (ReadWriteMode)
, hPutStrLn
)
import qualified Data.ByteString as BS
main = do
sock <- socket AF_INET6 Datagram defaultProtocol
let hints = defaultHints { addrFamily = AF_INET6, addrSocketType = Datagram}
serverAddr <- addrAddress . head <$> getAddrInfo (Just hints) (Just "::1") (Just "7331")
print serverAddr
bind sock serverAddr
print sock
forever $ do
receivedStuff <- recvFrom sock 65535 -- blocks
forkIO $ bracket newSendSocket close (serveReceive receivedStuff)
serveReceive :: (BS.ByteString, SockAddr) -> Socket -> IO ()
serveReceive (msg, fromAddr) sendSocket = do
putStrLn $ "Got message " ++ show msg ++ " from " ++ show fromAddr
sendTo sendSocket ("Hi, thx for " `BS.append` msg) fromAddr
putStrLn "sent response"
return ()
newSendSocket :: IO Socket
newSendSocket = socket AF_INET6 Datagram defaultProtocol
我正在使用netcat测试服务器的功能:nc -u -6 "localhost" 7331
服务器接收到消息,并能够将其放入标准输出。但是响应永远不会显示在netcat中。
知道我在做什么错吗?据我所知,在使用bind
发送数据之前,不需要绑定(connect
)或sendTo
数据报套接字。
您为什么要打开新的套接字进行发送?没必要如果您只是重新使用现有的套接字,那么一切正常。或者,我们可以使用wireshark进行查看。
使用新套接字进行响应(有问题的代码发布)
sendTo
返回值建议发送正确的字节数。查看鲨鱼时,我们会在电线上看到响应,但是该响应随后被ICMP目标端口不可访问拒绝(nc不接受来自其他端口的消息)。
使用原始插座*
如果我们不专门为响应创建套接字,而只是重新使用原始套接字,那么事情将按您期望的那样运行-就好了。