ReadBytes() delimiter param with 2 bytes

Hey there, I got a TCP socket read function that uses ReadBytes() function, I’m using 0x0A as delimiter but that’s not working because sometimes that 0x0A comes at the middle of the packet, what I really need is passing 0x0D 0x0A which means “\r\n”, but I found nothing like that. Below my code;

func (c *Client) listen() {
	reader := bufio.NewReader(c.conn)
	for {
		message, err := reader.ReadBytes(0x0A)
		if err != nil {
			c.conn.Close()
			c.Server.onClientConnectionClosed(c, err)
			return
		}
		c.Server.onNewMessage(c, hex.EncodeToString(message))
	}
}

Tnx.

Hey @leogazio,

It seems like you are trying to read a line at a time, is that the case?

If so, why not just use the ReadLine method. For example:

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	for {
		msg, _, err := reader.ReadLine()
		if err != nil {
			return
		}
		fmt.Printf("%s\n", msg)
	}
}

Or better yet, use a bufio.Scanner:

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		fmt.Printf("%s\n", scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		log.Fatalln(err)
	}
}
3 Likes

Hey Benjamin, I tried both both the 2 ones seems like they search for “\r” or “\n”, I really need searching for both at time, I searched here for a solution using scanner and found that one that works good;

// 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
}

And below the usage;

// Read client data from channel
func (c *Client) listen() {
	reader := bufio.NewReader(c.conn)
	scanner := bufio.NewScanner(reader)
	scanner.Split(ScanCRLF)
	for scanner.Scan() {
		c.Server.onNewMessage(c, strings.ToUpper(hex.EncodeToString(scanner.Bytes())+"0d0a"))
	}

}

You think is it a good practice in GO? The way I did…

Thanks.

Sure if that’s the functionality that you need, then you should use it :slight_smile:

All that’s doing is creating a new SplitFunc for the scanner based on the ScanLines splitting function which is the default for a bufio.Scanner, so it should work well, since the only difference between ScanLines and ScanCRLF is this:

if i := bytes.IndexByte(data, '\n'); i >= 0 {

Becomes this:

if i := bytes.Index(data, []byte{'\r', '\n'}); i >= 0 {

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.