Ошибка при отправке (или получении) данных в сокет (Haskell)

#sockets #networking #haskell #io #echo-server

#сокеты #сеть #haskell #io #echo-сервер

Вопрос:

Я возился с эхо-сервером, который нашел в Интернете, пытаясь разобраться в сетевом программировании с помощью Haskell, и наткнулся на камень преткновения. Кажется, я не могу понять, как отправить данные на сервер (с помощью другой программы или любым другим способом). Моя текущая попытка заключается в следующем:

 import Network (connectTo, Socket, PortID(..))
import System.IO (hPutStrLn, hClose, hSetBuffering, BufferMode(..))

main :: IO ()
main = do
  handle <- connectTo "127.0.0.1" (PortNumber 5555)
  hSetBuffering handle LineBuffering
  hPutStrLn handle "echo hello, world!"
  hPutStrLn handle "add 1 2"
  hClose handle
  

Когда я запускаю main, я получаю сообщение об ошибке «Server.hs: : hPutChar: ресурс исчез (сломанный канал)» в терминале, в котором запущен сервер. Серверный код выглядит следующим образом:

 import Network   (listenOn, accept, withSocketsDo, PortID(..), Socket)
import System    (getArgs)
import System.IO (hSetBuffering, hGetLine, hPutStrLn, BufferMode(..), Handle)
import Control.Concurrent (forkIO)

main :: IO ()
main = withSocketsDo $ do 
  args <- getArgs
  let port = fromIntegral (read $ head args :: Int)
  sock <- listenOn $ PortNumber port
  putStrLn $ "Listening on "    show port
  sockHandler sock

sockHandler :: Socket -> IO ()
sockHandler sock = do
  (handle, _, _) <- accept sock
  hSetBuffering handle NoBuffering
  forkIO $ commandProcessor handle
  sockHandler sock

commandProcessor :: Handle -> IO ()
commandProcessor handle = do
  line <- hGetLine handle
  let cmd = words line
  case (head cmd) of
    ("echo") -> echoCommand handle cmd
    ("add")  -> addCommand handle cmd
    _        -> do hPutStrLn handle "Unknown command."
  commandProcessor handle

echoCommand :: Handle -> [String] -> IO ()
echoCommand handle cmd = do
  hPutStrLn handle (unwords $ tail cmd)

addCommand :: Handle -> [String] -> IO ()
addCommand handle cmd = do
  hPutStrLn handle $ show $ (read $ cmd !! 1)   (read $ cmd !! 2)
  

Как мне это исправить? Я хочу приступить к расширению сервера, чтобы узнать больше. Спасибо!

Ответ №1:

В данном случае проблема проста. Вы записываете на сервер команду echo, а затем команду add, а затем отключаетесь. Затем сервер пытается обработать команду echo, а затем пытается выполнить обратную запись клиенту, но клиент уже отключен! следовательно, вы получаете исключение.

Клиент не может отключиться, пока не считает достаточное количество данных с сервера — и сервер должен обрабатывать исключения, чтобы отключение клиента не привело к его отключению.