gpt4 book ai didi

Haskell 服务器不回复客户端

转载 作者:行者123 更新时间:2023-12-02 23:48:50 26 4
gpt4 key购买 nike

我尝试按照 this tutorial 构建一个简单的客户端-服务器程序关于 Haskell 的网络管道库。

这是客户端,它同时向服务器发送文件并接收答案:

{-# LANGUAGE OverloadedStrings #-}

import Control.Concurrent.Async (concurrently)
import Data.Functor (void)

import Conduit
import Data.Conduit.Network

main = runTCPClient (clientSettings 4000 "localhost") $ \server ->
void $ concurrently
(runConduitRes $ sourceFile "input.txt" .| appSink server)
(runConduit $ appSource server .| stdoutC)

这是服务器,它计算每个单词的出现次数并将结果发送回客户端:

{-# LANGUAGE OverloadedStrings #-}

import Data.ByteString.Char8 (pack)
import Data.Foldable (toList)
import Data.HashMap.Lazy (empty, insertWith)
import Data.Word8 (isAlphaNum)

import Conduit
import Data.Conduit.Network
import qualified Data.Conduit.Combinators as CC

main = runTCPServer (serverSettings 4000 "*") $ \appData -> do
hashMap <- runConduit $ appSource appData
.| CC.splitOnUnboundedE (not . isAlphaNum)
.| foldMC insertInHashMap empty
runConduit $ yield (pack $ show $ toList hashMap)
.| iterMC print
.| appSink appData

insertInHashMap x v = do
return (insertWith (+) v 1 x)

问题是,在我手动关闭客户端之前,服务器不会到达屈服阶段,因此永远不会回答它。我注意到,从客户端删除并发并仅保留将数据发送到服务器的部分,一切正常。

那么,如何在不破坏流程的情况下保留客户端的接收部分呢?

最佳答案

出现死锁:客户端在关闭连接之前等待服务器响应,但服务器不知道客户端已完成发送数据并正在等待更多数据。这基本上就是 https://cr.yp.to/tcpip/twofd.html 中描述的问题。 :

When the generate-data program finishes, the same fd is still open in the consume-data program, so the kernel has no idea that it should send a FIN.

就您而言,修复需要在客户端进行。您需要调用shutdownShutdownSend一旦 conduit 完成通过套接字发送 input.txt 的内容,就在套接字上。

这是一种方法(我不确定是否有更好的方法):

{-# LANGUAGE OverloadedStrings #-}

import Control.Concurrent.Async (concurrently)
import Data.Functor (void)
import Data.Foldable (traverse_)

import Conduit
import Data.Conduit.Network

import Data.Streaming.Network (appRawSocket)
import Network.Socket (shutdown, ShutdownCmd(..))

main = runTCPClient (clientSettings 4000 "localhost") $ \server ->
void $ concurrently
((runConduitRes $ sourceFile "input.txt" .| appSink server) >> doneWriting server)
(runConduit $ appSource server .| stdoutC)

doneWriting = traverse_ (`shutdown` ShutdownSend) . appRawSocket

旁注:在这种情况下,您实际上不需要客户端中的并发性,因为在完成向服务器的写入之前,永远不会从服务器读取任何内容。您可以在写入并关闭后进行读取。

关于Haskell 服务器不回复客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56177515/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com