目标无法访问(端口无法访问)使用Haskell

时间:2014-08-05 19:41:34

标签: sockets haskell client-server

使用Wireshark进行调试,在localhost上发送UDP数据包时收到以下错误:

Destination Unreachable (Port Unreachable)

Checksum: 0x0000 (Illegal)

我首先使用

在10000到15000之间的端口上构建我的服务器
startServer :: Port -> IO Server
startServer port = withSocketsDo $ do
  -- Look up the server address and port information.
  addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
  let serverAddress = head addrs

  -- Bind to the socket.
  sock <- socket (addrFamily serverAddress) Datagram defaultProtocol
  bindSocket sock (addrAddress serverAddress)

  -- Create the server and run the client send and receive threads.
  clients  <- newMVar $ createEmptyClients
  let server = Server sock port clients
  _ <- forkIO $ forever $ receiveClientJoin server
  return server

我正在侦听使用

通过UDP连接的新客户端
-- | Connected a client to the server.
receiveClientJoin :: Server -> IO ()
receiveClientJoin server = do
  print "Receiving"
  (msg, _, clSockAddr) <- recvFrom (sSocket server) 4096
  print $ "Server received client join message: " ++ msg

我正在使用

连接到客户端的服务器
connectToServer port = do
  -- Get the server's address and port information.
  addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
  let serverAddr = head addrInfo
  sock  <- socket (addrFamily serverAddr) Datagram defaultProtocol
  sendTo sock "Hello from this client!" (addrAddress serverAddr)

为什么我的客户端的数据包没有找到服务器?

1 个答案:

答案 0 :(得分:1)

问题是您正在侦听IPv6地址并尝试连接到IPv4地址。这实际上是一个常见的问题。例如,我在使用commsec时遇到了此问题。

考虑您发现AddrInfo

的片段
import Network.Socket 

main :: IO ()
main = do
  let port = "2474"
  addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
  let serverAddress = head addrs
  print serverAddress

  addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
  let serverAddr = head addrInfo
  print serverAddr

现在输出会因机器而异,但在我的一个同时具有IPv4和IPv6地址的CentOS系统上,输出清楚地显示第二个(连接)地址是IPv6,而第一个(监听)地址是IPv4:

AddrInfo {addrFlags = [AI_PASSIVE], addrFamily = AF_INET, addrSocketType = Stream, addrProtocol = 6, addrAddress = 0.0.0.0:2474, addrCanonName = Nothing}
AddrInfo {addrFlags = [AI_ADDRCONFIG,AI_V4MAPPED], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [::1]:2474, addrCanonName = Nothing}

一种解决方案是通过提示或地址(例如我的评论中的IPv4地址)强制使用特定版本的IP。提示解决方案可能更合适:

-- For servers:
  addrs <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6
                                          , addrFlags = [AI_PASSIVE] })
                       Nothing (Just port)
-- For clients:
addrInfo <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6 })
                        (Just "localhost") (Just port)