【问题标题】:F# Trying to write HTTP response to TCP streamF# 尝试将 HTTP 响应写入 TCP 流
【发布时间】:2016-04-02 19:48:46
【问题描述】:

我正在尝试在 F# 中创建一个简单的 HTTP 服务器。但不幸的是,我被困在响应阶段,我正在尝试创建一个简单的 404 响应,但我的浏览器无法获得它,它只会永远加载和加载页面,不会去任何地方。我不知道我的代码哪里出错了。

let responseString = "HTTP/1.1 404 NOT FOUND";
let buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

let processRequest (client: TcpClient)  = 
    async {  do printfn "Incoming HTTP request..."
             use stream = client.GetStream()
             use sr = new StreamReader(stream)
             let! content = sr.ReadToEndAsync() |> Async.AwaitTask
             do 
                printfn "Stream contains:\n%s" content 
                stream.Write(buffer, 0, buffer.Length) 
                stream.Flush() }

let ip = IPAddress.Parse("127.0.0.1")
let listener = TcpListener(ip, 8080)
let startServer = 
    async { do listener.Start() 
            do printfn "Starting server..."
            while true do 
                let! context = listener.AcceptTcpClientAsync() |> Async.AwaitTask
                do! processRequest context }

Async.Start startServer

【问题讨论】:

  • 您是否尝试过使用调试器单步执行代码?
  • 您是否尝试过阅读标准或至少查看一些工作示例?这不是你正在做的 HTTP (没有正确的行结束,没有标题的结尾)。
  • @SteffenUllrich 是的,我已经阅读了许多工作示例,但几乎所有示例都使用 HttpListener 类,它可以为我完成大部分工作。
  • 如果你想自己实现HTTP,那么你最好阅读standard。但我在第一次评论中给出了一些明显错误的提示。

标签: http tcp f#


【解决方案1】:

问题是,TCP 流不知道客户端何时发送了所有数据(除非您关闭浏览器),因此 StreamReader 被永远阻塞。 如果您想自己实现 HTTP,您需要(对于初学者)逐行阅读并检查是否允许客户端发送更多数据。

【讨论】:

  • 哦,好吧,那么实际上这里的问题是阅读问题?这解释了一些事情。所以我必须去阅读关于 HTTP 请求的规范?
【解决方案2】:

正如@CaringDev 指出的那样,ReadToEnd 不会终止。也就是说,对于一个简单的 HTTP 服务器,您只需要阅读请求的第一行。这是您的代码的更新版本,它仅读取第一行并以 200 OK 响应:

open System.Net

let processRequest (client: Sockets.TcpClient) = async {  
  printfn "Incoming HTTP request..."
  use stream = client.GetStream()
  use sr = new System.IO.StreamReader(stream)
  let line = sr.ReadLine()
  printfn "Request: %s" line
  let sw = new System.IO.StreamWriter(stream)
  sw.WriteLine("HTTP/1.1 200 OK\r\n\r\nHello World")
  sw.Flush()     
  }

let ip = IPAddress.Parse("127.0.0.1")
let listener = Sockets.TcpListener(ip, 8080)
let startServer = async { 
  do listener.Start() 
  do printfn "Starting server..."
  while true do 
    let! context = listener.AcceptTcpClientAsync() |> Async.AwaitTask
    processRequest context |> Async.Start
  }

Async.Start startServer

我也很想将do! processRequest context 更改为processRequest context |> Async.Start,以便您可以同时处理多个请求。

【讨论】:

    猜你喜欢
    • 2012-08-08
    • 2011-02-25
    • 2018-07-08
    • 2011-08-15
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多