Error handling 如何正确读取具有帧边界的字节流,并在F#中进行错误处理?

Error handling 如何正确读取具有帧边界的字节流,并在F#中进行错误处理?,error-handling,io,f#,Error Handling,Io,F#,我是F#的新手,需要帮助解决这个问题 我有一个字节流,它来自串行端口,用F#表示为序列。流由帧组成,每个帧以0xFE开始,以0xFF结束。字节连续传输,为了同步,我必须跳过一些字节,直到0xFE。但流可能已损坏,并且可能缺少0xFE或0xFF 我有一个函数,它通过串行端口的输入进行迭代。功能代码为: let getFrame s = let r = s |> Seq.skipWhile (fun x->x<>0xFEuy) |>

我是F#的新手,需要帮助解决这个问题

我有一个字节流,它来自串行端口,用F#表示为序列。流由帧组成,每个帧以0xFE开始,以0xFF结束。字节连续传输,为了同步,我必须跳过一些字节,直到0xFE。但流可能已损坏,并且可能缺少0xFE或0xFF

我有一个函数,它通过串行端口的输入进行迭代。功能代码为:

let getFrame s =
    let r = s |> Seq.skipWhile (fun x->x<>0xFEuy) 
              |> Seq.takeWhile (fun x->x<>0xFFuy)
    if Seq.isEmpty r then r else Seq.skip 1 r
让我们获取帧s=
让r=s |>Seq.skipWhile(乐趣x->x0xFEuy)
|>Seq.takeWhile(乐趣x->x0xFFuy)
如果序号为空,则序号为,否则跳过1 r
如何重写此代码以跳过字节直到0xFE或跳过一定数量的字节,如果没有发生0xFE,则以函数方式返回错误


在0xFF之前获取帧字节的tru也是如此。

您可以使用
选项我认为下面的函数可以满足您的需要。输入流由垃圾和帧组成。Gargabe可以放在第一位,也可以放在两帧之间。如果垃圾太多或帧太长,则会报告错误。否则将返回下一帧

let [<Literal>] FrameStart = 0xFE
let [<Literal>] FrameEnd = 0xFF

let [<Literal>] MaxGarbageLength = 5
let [<Literal>] MaxFrameLength = 5

type State<'T> =
| Garbage of int
| Frame of int * 'T list

let getFrame stream =
    let getNextRest stream =
        match Seq.isEmpty stream with
        | true -> None
        | false -> Some(Seq.head stream, Seq.skip 1 stream)

    let rec parse state stream =
        match getNextRest stream with
        | None -> None
        | Some(next, rest) ->
            match state with
            | Garbage n when n >= MaxGarbageLength -> None
            | Garbage n ->
                match next with
                | FrameStart -> parse (Frame(0, [])) rest
                | _ -> parse (Garbage(n+1)) rest
            | Frame(n, _) when n >= MaxFrameLength -> None
            | Frame(n, content) ->
                match next with
                | FrameEnd -> Some(content, rest)
                | _ -> parse (Frame(n+1, content @ [next])) rest

    parse (Garbage 0) stream
let[]FrameStart=0xFE
设[]FrameEnd=0xFF
设[]MaxGarbageLength=5
设[]MaxFrameLength=5
类型状态无
|false->Some(序列头流,序列跳过1流)
让rec解析状态流=
将getNextRest流与
|无->无
|一些(下一步,休息)->
匹配状态
|垃圾n当n>=MaxGarbageLength->None时
|垃圾n->
下一个匹配
|FrameStart->parse(框架(0,[])rest
|>解析(垃圾(n+1))rest
|当n>=MaxFrameLength->None时的帧(n,ux)
|框架(n,内容)->
下一个匹配
|FrameEnd->Some(内容,其余)
|>解析(框架(n+1,内容@[next])rest
解析(垃圾0)流
要从流中获取两帧,请执行以下操作:

[<Test>]
let ``can parse two frames with garbage in between``() =
    let stream = Seq.ofList [1;2;3;FrameStart;4;5;6;FrameEnd;7;8;FrameStart;9;0;FrameEnd]

    let (frame1, rest) = (getFrame stream).Value
    frame1 |> should equal [4;5;6]
    rest |> should equal [7;8;FrameStart;9;0;FrameEnd]

    let (frame2, rest) = (getFrame rest).Value
    frame2 |> should equal [9;0]
    rest |> should equal []
[]
让``可以分析两个帧,垃圾在``()=
让流=列表的顺序[1;2;3;FrameStart;4;5;6;FrameEnd;7;8;FrameStart;9;0;FrameEnd]
let(frame1,rest)=(getframestream).Value
框架1 |>应等于[4;5;6]
rest |>应等于[7;8;FrameStart;9;0;FrameEnd]
let(frame2,rest)=(getframerest).Value
框架2 |>应等于[9;0]
rest |>应等于[]
返回None可正确检测错误(注意MaxGarbagelLength为5,因此以下报告错误):

[]
当垃圾太多时,让“无”返回()=
让流=[1;2;3;4;5;6;帧开始;7;8;9;帧结束]
(getFrame stream).IsNone |>应等于true

这似乎可行,应该很容易扩展/修改。但对我来说,这看起来像是一段代码。欢迎改进。

谢谢您的回答!但是,如果流中有垃圾并且没有0xFE(帧开始),例如在前1000个字节中,我如何正确地停止skipWhile呢。А以及如何在中途停止的情况下区分正确的帧开始和错误(未找到0xFE)?您可能希望编辑此问题以添加一些示例。我的理解是,您需要帮助编写函数,以便从开始跳到0xFE,从0xFF跳到结束,而不是处理错误。@GuyCoder,是的,您是对的!
[<Test>]
let ``can parse two frames with garbage in between``() =
    let stream = Seq.ofList [1;2;3;FrameStart;4;5;6;FrameEnd;7;8;FrameStart;9;0;FrameEnd]

    let (frame1, rest) = (getFrame stream).Value
    frame1 |> should equal [4;5;6]
    rest |> should equal [7;8;FrameStart;9;0;FrameEnd]

    let (frame2, rest) = (getFrame rest).Value
    frame2 |> should equal [9;0]
    rest |> should equal []
[<Test>]
let ``none is returned when there is too much garbage``() =
    let stream = [1;2;3;4;5;6;FrameStart;7;8;9;FrameEnd]
    (getFrame stream).IsNone |> should equal true