27
votes

To teach myself Go I'm building a simple server that takes some input, does some processing, and sends output back to the client (that includes the original input).

The input can vary in length from around 5 - 13 characters + endlines and whatever other guff the client sends.

The input is read into a byte array and then converted to a string for some processing. Another string is appended to this string and the whole thing is converted back into a byte array to get sent back to the client.

The problem is that the input is padded with a bunch of NUL characters, and I'm not sure how to get rid of them.

So I could loop through the array and when I come to a nul character, note the length (n), create a new byte array of that length, and copy the first n characters over to the new byte array and use that. Is that the best way, or is there something to make this easier for me?

Some stripped down code:

data := make([]byte, 16)
c.Read(data)

s := strings.Replace(string(data[:]), "an", "", -1)
s = strings.Replace(s, "\r", "", -1)
s += "some other string"
response := []byte(s)
c.Write(response)
c.close()

Also if I'm doing anything else obviously stupid here it would be nice to know.

4

4 Answers

60
votes

In package "bytes", func Trim(s []byte, cutset string) []byte is your friend:

Trim returns a subslice of s by slicing off all leading and trailing UTF-8-encoded Unicode code points contained in cutset.

// Remove any NULL characters from 'b'
b = bytes.Trim(b, "\x00")
4
votes

Your approach sounds basically right. Some remarks:

  1. When you have found the index of the first nul byte in data, you don't need to copy, just truncate the slice: data[:idx].

  2. bytes.Index should be able to find that index for you.

  3. There is also bytes.Replace so you don't need to convert to string.

0
votes

You could utilize the return value of Read:

package main
import "strings"

func main() {
   r, b := strings.NewReader("north east south west"), make([]byte, 16)
   n, e := r.Read(b)
   if e != nil {
      panic(e)
   }
   b = b[:n]
   println(string(b) == "north east south")
}

https://golang.org/pkg/io#Reader

0
votes

The io.Reader documentation says:

Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.

If the call to Read in the application does not read 16 bytes, then data will have trailing zero bytes. Use the number of bytes read to trim the zero bytes from the buffer.

data := make([]byte, 16)
n, err := c.Read(data)
if err != nil {
   // handle error
}
data = data[:n]

There's another issue. There's no guarantee that Read slurps up all of the "message" sent by the peer. The application may need to call Read more than once to get the complete message.

You mention endlines in the question. If the message from the client is terminated but a newline, then use bufio.Scanner to read lines from the connection:

 s := bufio.NewScanner(c)
 if s.Scan() {
     data = s.Bytes() // data is next line, not including end lines, etc.
 }
 if s.Err() != nil {
     // handle error
 }