dpkt17803 2017-10-22 20:47
浏览 100
已采纳

不必要的空格添加到通过TCP发送的字符串中

I'm attempting to learn Go, and the first thing I've tried is sending files between a client and server using TCP. I set up a connection using net.Listen, and connect using net.Dial. My client logic is:

  1. Send an int64 using binary.Write describing the size of the filename
  2. Send the filename using io.WriteString
  3. Send an int64 describing the size of the file
  4. Send the file using io.CopyN

My server logic is:

  1. Read 8 bytes using binary.Read, save as N
  2. Read N bytes to get the filename, which is read into a bytes.NewBuffer(make([]byte, filenameSize)) that has String() subsequently called on it
  3. Read 8 bytes to get the filesize, save as M
  4. io.CopyN from the connection into a new file object for M bytes.

My problem is something totally baffling to me, which I haven't been able to solve or understand, and for which I can find no discussion or solution on Google or SO: even though the filename length is transmitted accurately, the server always receives a filename of twice the expected length, where the first half is whitespace. Even more bafflingly, using strings.TrimLeft(filename, " ") never works, even though it works for strings I create myself.

So I have absolutely no idea what's going on, and nothing in the docs, SO, Google, go-nuts, etc mentions anything that could seem relevant. No idea how to move forward or think about this problem, I'd love some help.

My server handler:

func handle(conn net.Conn) {
    defer conn.Close()
    conn.SetReadDeadline(time.Now().Add(time.Second * 30))

    var filenameSize int64
    err := binary.Read(conn, binary.LittleEndian, &filenameSize)
    check(err)

    filename := bytes.NewBuffer(make([]byte, filenameSize))
    bytesRead, err := io.CopyN(filename, conn, filenameSize)
    fmt.Printf("Expected %d bytes for filename, read %d bytes
", filenameSize, bytesRead)
    str := filename.String()
    fmt.Println(strings.TrimLeft(str, " "))

    var filesize int64
    err = binary.Read(conn, binary.LittleEndian, &filesize)
    check(err)
    fmt.Printf("Expecting %d bytes in file
", filesize)

    f, err := os.Create(str)
    check(err)
    bytesWritten, err := io.CopyN(f, conn, filesize)
    check(err)
    fmt.Printf("Transfer complete, expected %d bytes, wrote %d bytes", filesize, bytesWritten)
    if filesize != bytesWritten {
        fmt.Printf("ERROR! File doesn't match expected size!")
    }
}

My client:

func main() {
    name := "test_file.doc"

    conn, err := net.Dial("tcp", "localhost:8250")
    check(err)

    length := int64(len(name))
    err = binary.Write(conn, binary.LittleEndian, length)
    check(err)

    bytes, err := io.WriteString(conn, name)
    check(err)
    if bytes != len(name) {
        fmt.Printf("Error! Wrote %d bytes but length of name is %d!
", bytes, length)
    }

    f, err := os.Open(name)
    check(err)

    stat, err := f.Stat()
    check(err)

    filesize := stat.Size()
    err = binary.Write(conn, binary.LittleEndian, filesize)
    check(err)

    bytesWritten, err := io.CopyN(conn, f, filesize)
    check(err)
    if bytesWritten != filesize {
        fmt.Printf("Error! Wrote %d bytes but length of file is %d!
", bytes, stat.Size())
    }
}
  • 写回答

2条回答 默认 最新

  • duanjiaolia97750 2017-10-22 21:28
    关注

    The Go Programming Language Specification

    Allocation

    Making slices, maps and channels

    Call             Type T     Result
    
    make(T, n)       slice      slice of type T with length n and capacity n
    make(T, n, m)    slice      slice of type T with length n and capacity m
    

    Package bytes

    import "bytes"
    

    func NewBuffer

    func NewBuffer(buf []byte) *Buffer

    NewBuffer creates and initializes a new Buffer using buf as its initial contents. The new Buffer takes ownership of buf, and the caller should not use buf after this call. NewBuffer is intended to prepare a Buffer to read existing data. It can also be used to size the internal buffer for writing. To do that, buf should have the desired capacity but a length of zero.

    In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.


    bytes.NewBuffer can be used to size the internal buffer for writing. To do that, buf should have the desired capacity but a length of zero. For example, with a length of zero and a capacity of filenameSize,

    filename := bytes.NewBuffer(make([]byte, 0, filenameSize))
    

    In error, you allocated buf with a length and capacity of filenameSize,

    filename := bytes.NewBuffer(make([]byte, filenameSize))
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分