【问题标题】:haskell acceptFork for http server用于 http 服务器的 haskell acceptFork
【发布时间】:2015-04-27 05:34:20
【问题描述】:

我必须在 haskell 中创建一个 http 服务器。为此,我必须定义一个 acceptFork 函数来处理传入的 TCP 连接,它具有以下类型:

acceptFork :: Socket -> (Handle -> IO ()) -> IO ()

它的工作方式如下:

  • 使用accept函数接受传入的连接,该连接返回一个Handle
  • 使用 hSetBuffering 函数禁用缓冲(将值设置为 NoBuffering)
  • 使用 hSetNewlineMode 函数设置新行字符(使用参数 (NewlineMode CRLF CRLF))
  • 启动一个新线程,对句柄值运行输入操作
  • 递归地等待下一个连接

到目前为止,我想出的是:

import qualified Network.Socket as NS

acceptFork :: Socket -> (Handle -> IO ()) -> IO ()
acceptFork lsock k = do
    (csock,_) <- NS.accept lsock
    hSetBuffering lsock NoBuffering
    hSetNewlineMode lsock (NewlineMode CRLF CRLF)
    forkIO (k csock) 

问题是它甚至无法编译。有人可以解释我做错了什么吗?谢谢!

这是我得到的错误:

bead2.hs:31:23:
Couldn't match expected type `(Handle -> BufferMode -> IO ())
                              -> Socket
                              -> BufferMode
                              -> (Handle -> NewlineMode -> IO ())
                              -> Socket
                              -> NewlineMode
                              -> IO (Handle, t0)'
            with actual type `IO (Socket, NS.SockAddr)'
The function `NS.accept' is applied to 7 arguments,
but its type `Socket -> IO (Socket, NS.SockAddr)' has only one
In a stmt of a 'do' block:
  conn@(csock, _) <- NS.accept
                       lsock
                       hSetBuffering
                       lsock
                       NoBuffering
                       hSetNewlineMode
                       lsock
                       (NewlineMode CRLF CRLF)
In the expression:
  do { conn@(csock, _) <- NS.accept
                            lsock
                            hSetBuffering
                            lsock
                            NoBuffering
                            hSetNewlineMode
                            lsock
                            (NewlineMode CRLF CRLF);
       forkIO (k csock) }

bead2.hs:34:5:
Couldn't match type `ThreadId' with `()'
Expected type: IO ()
  Actual type: IO ThreadId
In a stmt of a 'do' block: forkIO (k csock)
In the expression:
  do { conn@(csock, _) <- NS.accept
                            lsock
                            hSetBuffering
                            lsock
                            NoBuffering
                            hSetNewlineMode
                            lsock
                            (NewlineMode CRLF CRLF);
       forkIO (k csock) }

【问题讨论】:

  • 首先请添加您收到的错误消息 - 谢谢
  • btw:最初的大部分内容来自 indentation 问题,我认为是在您将代码复制并粘贴到 Stack-Overflow 时引入的 - 但它看来您真的打算将其全部达到acceptFork 的水平(我错误地编辑了;))

标签: haskell tcplistener


【解决方案1】:

好的,我复制了你的内容并添加了缺失的部分(对于网络 > 2.6 和

import qualified Network.Socket as NS
import System.IO (Handle, hSetBuffering, hSetNewlineMode, BufferMode(..), Newline(..), NewlineMode(..), IOMode(..))
import Control.Concurrent (forkIO, ThreadId)

acceptFork :: NS.Socket -> (Handle -> IO ()) -> IO ThreadId
acceptFork lsock k = do
    (csock,_) <- NS.accept lsock
    hsock <- NS.socketToHandle csock ReadWriteMode
    hSetBuffering hsock NoBuffering
    hSetNewlineMode hsock (NewlineMode CRLF CRLF)
    forkIO (k hsock)

基本上你有:

  • 大量缺失的导入
  • 需要通过NS.socketToHandle从socket获取句柄
  • 注意forkIO(新线程的ID)的结果

编译如下:

 base >=4.8 && <4.9, network >=2.6 && <2.7

免责声明

我确实没有运行此代码,所以我不知道它是否有效 - 但它会编译(在我的系统上;))

没有ThreadId:

只需更改签名和最后一行:

acceptFork :: NS.Socket -> (Handle -> IO ()) -> IO ()
acceptFork lsock k = do
    -- ... same as above
    _ <- forkIO (k hsock)
    return ()

fork 并等待下一个连接:

只需递归调用acceptFork

acceptFork :: NS.Socket -> (Handle -> IO ()) -> IO ()
acceptFork lsock k = do
    (csock,_) <- NS.accept lsock
    hsock <- NS.socketToHandle csock ReadWriteMode
    hSetBuffering hsock NoBuffering
    hSetNewlineMode hsock (NewlineMode CRLF CRLF)
    _ <- forkIO (k hsock)
    acceptFork lsock k

或使用forever

...
import Control.Monad (forever)

acceptFork :: NS.Socket -> (Handle -> IO ()) -> IO ()
acceptFork lsock k = ...

acceptAll :: NS.Socket -> (Handle -> IO ()) -> IO ()
acceptAll sock = forever . acceptFork sock 

【讨论】:

  • 谢谢。还有两个问题: 1. 我应该如何处理线程的 id?我什至需要它吗? 2.我应该在哪里递归调用这个函数才能处理下一个客户端?
  • 顺便说一句,现在我只收到一个错误:Couldn't match type ThreadId' 和 ()' Expected type: IO () Actual type: IO ThreadId
  • 如果你不需要 id 就忽略它 - 你应该如何称呼它?好吧,也许您可​​能想递归调用它以等待下一个调用者 - 但这取决于您的问题
  • 您收到新错误是因为您没有更改 acceptFork 的签名或您使用它的位置 - 我将编辑掉 ThreadId
  • 顺便说一句:为什么还要编写自己的 HTTP 服务器?那里有很多(寻找Scotty,如果你需要一个非常轻量级的) - 如果你想尝试,我理解它,但如果你想快速获得结果,最好寻找一个框架
猜你喜欢
  • 2010-09-28
  • 2018-08-24
  • 2021-03-12
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
相关资源
最近更新 更多