2016-05-30 15 views
2

私は自分のbeanstalkdクライアントを学習の方法として実装しようとしています。 https://github.com/kr/beanstalkd/blob/master/doc/protocol.txtgolang-bufio(CRLF) r nデリミタまで

現時点では、私は\nで区切られたデータ行を読むためにbufioを使用しています。

res, err := this.reader.ReadLine('\n')

これは私が単一のコマンドを送信する、などAA一行応答読んだときの罰金です:INSERTED %d\r\nをしかし、私は仕事のボディはとのように複数行になる可能性があるため、仕事を確保しようとすると、私は困難を見つけますそのような私は、区切り文字\nを使用することはできません。

CRLFまでバッファに読み込む方法はありますか?

私はreserveコマンドを送信します。私の予想される応答は次のとおりです。

RESERVED <id> <bytes>\r\n 
<data>\r\n 

しかし、データが\n含まれている可能性があり、私は\r\nまで読む必要があります。

また、上記の例の応答で<bytes>に指定されている特定のバイト数を読み取る方法がありますか?

func (this *Bean) receiveLine() (string, error) { 
    res, err := this.reader.ReadString('\n') 
    return res, err 
} 

func (this *Bean) receiveBody(numBytesToRead int) ([]byte, error) { 
    res, err := this.reader.ReadString('\r\n') // What to do here to read to CRLF/up to number of expected bytes? 

    return res, err 
} 

func (this *Bean) Reserve() (*Job, error) { 

    this.send("reserve\r\n") 
    res, err := this.receiveLine() 

    var jobId uint64 
    var bodylen int 
    _, err = fmt.Sscanf(res, "RESERVED %d %d\r\n", &jobId, &bodylen) 

    body, err := this.receiveBody(bodylen) 

    job := new(Job) 
    job.Id = jobId 
    job.Body = body 

    return job, nil 
} 

答えて

6

解像度を、ERR:

現時点で

に、私は(削除取り扱いを誤る)持っている= this.reader.Read( '\ n')で

はなりません私には何の意味もありません。 ReadBytes/ReadSlice/ReadStringを意味しましたか?

あなたはbufio.Scannerが必要です。

あなたのbufio.SplitFuncを定義してください(例はbufio.ScanLinesのコピーで、 '\ r \ n'を探します)。あなたのケースに合わせて修正してください。

// dropCR drops a terminal \r from the data. 
func dropCR(data []byte) []byte { 
    if len(data) > 0 && data[len(data)-1] == '\r' { 
     return data[0 : len(data)-1] 
    } 
    return data 
} 


func ScanCRLF(data []byte, atEOF bool) (advance int, token []byte, err error) { 
     if atEOF && len(data) == 0 { 
      return 0, nil, nil 
     } 
     if i := bytes.Index(data, []byte{'\r','\n'}); i >= 0 { 
      // We have a full newline-terminated line. 
      return i + 2, dropCR(data[0:i]), nil 
     } 
     // If we're at EOF, we have a final, non-terminated line. Return it. 
     if atEOF { 
      return len(data), dropCR(data), nil 
     } 
     // Request more data. 
     return 0, nil, nil 
    } 

ここで、io.Readerをカスタムスキャナでラップします。スキャナについて

scanner := bufio.NewScanner(this.reader) 
scanner.Split(ScanCRLF) 
// Set the split function for the scanning operation. 
scanner.Split(split) 
// Validate the input 
for scanner.Scan() { 
     fmt.Printf("%s\n", scanner.Text()) 
} 

if err := scanner.Err(); err != nil { 
     fmt.Printf("Invalid input: %s", err) 
} 

読むbufio package'sソースコード。

また、上記の例の応答で指定されている特定のバイト数を読み取る方法がありますか?

まず、「予約済み\ r \ n」の行をいくつか見てみる必要があります。

そして、あなたは

nr_of_bytes : = read_number_of_butes_somehow(this.reader) 
buf : = make([]byte, nr_of_bytes) 
this.reader.Read(buf) 

またはLimitedReaderを使用することができます。

しかし、私はこのアプローチが好きではありません。

ありがとうございます。Read( '\ n')はタイプミスでした。私は質問を修正しました。私はこれまでに得た場所のサンプルコードも添付しました。ご覧のとおり、ボディの予想バイト数を取得できます。特定のバイト数を読んでいるのが好きではない理由を詳しく説明できますか?これは最も論理的なようですか?

私はBeanの定義、特に読者の部分を見たいと思います。 何とかこのカウンターが間違っていると想像してください。

  1. その短い: "\ r \ n"を見つけてその時点までのすべてを破棄する必要がありますか?か否か?どうして最初にカウンターが必要ですか?

  2. そのサイズが大きいほど(またはさらに巨大になるはずです)。

    2.1読者に次のメッセージはありません。

    2.2次のメッセージが表示されます。バウ、その一部を読んでいて、簡単に回復する方法はありません。

    2.3メッセージの大きさ:メッセージが1バイトであってもメモリを割り当てることはできません。

このバイトカウンタは一般にメッセージを検証するように設計されています。 これは、Beanstalkdプロトコルの場合のようです。

使用スキャナ、予想される数と長さを確認し、メッセージを解析...利益

UPD

が警告され、デフォルトbufio.Scannerは64K、その後続きを読むカント、scanner.Bufferと最大長さを設定します最初。あなたはこのオプションをオンザフライで変更することができず、一部のデータがスキャナによって「あらかじめ」読み込まれていた可能性があるので、それは悪いことです。

UPD2

私の最後の更新を考えます。 net.textprotoを見て、それが単純なステートマシンのようにdotReaderをどのように実装しているかを見てください。最初にコマンドを読み、ペイロードで "expected bytes"をチェックするのと同様のことができます。

+0

ありがとうございます - 'reader.Read( '\ n')'はタイプミスでした。私は質問を修正しました。私はこれまでに得た場所のサンプルコードも添付しました。ご覧のとおり、ボディの予想バイト数を取得できます。特定のバイト数を読んでいるのが好きではない理由を詳しく説明できますか?これは最も論理的なようですか? – Gravy

+0

回答がポストに追加されました。 – Darigaaz

関連する問題