dqpu4988 2015-09-03 08:31
浏览 22

二进制。在go块中写入套接字

I'm trying to write a simple client-server application. It works fine with both sides on the same computer, but it blocks when run on two different computers. The computers are a RaspBerry Pi 2 and a MacBook Pro.

The problem is that the client blocks in binary.Write after a few good runs. Typically, the server that receives the data prints that it has received 63 and the client that sends the data prints that it will be sending 64.

If I ad the deadline to the server, it quits with a time-out. The client also has a deadline but doesn't time out.

I tried replacing the data by a simple byte array or just a single int. It still blocks. But the smaller the data is, the more times it goes right.

If I remove the Printf functions in the client, it also goes well for a longer time.

I also tried replacing the functionality of the server by a simple copy from the socket to STDIO (a tip I found here somewhere) but it still fails to come out of binary.Write.

Any idea?

Here is the complete source. There's some bogus stuff in there (the count loop, for example), but it's all really quite simple. Or am I mistaken?

package main

import (
    //  "bytes"
    "encoding/binary"
    "fmt"
    "io"
    "net"
    "os"
    "os/exec"
    "runtime/trace"
    "time"
    "unsafe"
)

type TheMessageType struct {
    X             int32
    RestOfMessage [1000]byte
}

func listener(theCounter int, active bool, f *os.File) {
    var message TheMessageType
    var err error
    var conn net.Conn

    count := theCounter

    for {
        // Dial the server
        fmt.Printf("LISTENER %d: connecting to socket
", count)
        conn, err = net.Dial("tcp", "192.168.1.113:49152")
        if err != nil {
            fmt.Printf("LISTENER %d: not connected, retrying in 3 seconds
", count)
            time.Sleep(3 * time.Second)
        } else {
            fmt.Printf("LISTENER %d: connected
", count)
            break
        }
    }
    defer conn.Close()

    // Loop writing to socket
    for {
        // Set deadline
        // conn.SetDeadline(time.Now().Add(2 * time.Second))

        // Print some info
        fmt.Printf("LISTENER %d: writing from %v to %v
", count, conn.LocalAddr(), conn.RemoteAddr())

        // Prepare message to write to socket
        message.X = int32(count)
        theString := fmt.Sprintf("%d", count)
        copy(message.RestOfMessage[:], theString)

        // binary write directly to socket
        fmt.Printf("LISTENER %d: binary.Write this: %d, %s
", count, message.X, message.RestOfMessage)

        f.Sync()
        err = binary.Write(conn, binary.LittleEndian, message)

        f.Sync()
        fmt.Printf("LISTENER %d: written
", count)
        // time.Sleep(50 * time.Millisecond)
        checkError(err, "LISTENER")

        count = count + 1
    }
}

func main() {
    var myMessage TheMessageType
    var ln net.Listener
    var conn net.Conn
    var err error
    var theCount int
    var avgspeed, speed float64
    var speedlist [10]float64

    curspeed := 0

    const listenerActive = true
    const mainActive = false

    f, err := os.Create("theFile.out")
    trace.Start(f)

    t0 := time.Now()
    t1 := time.Now()

    transferSize := unsafe.Sizeof(myMessage)

    fmt.Printf("MAIN: timestamp %s ; size of transfers is %d
", t0.String(), transferSize)

    if mainActive {
        fmt.Println("MAIN: listen")
        ln, err = net.Listen("tcp", ":49152")
        fmt.Println("MAIN: defer")
        defer ln.Close()
        fmt.Println("MAIN: checkError")
        checkError(err, "MAIN")
    }

    // launch listener
    if listenerActive {
        go listener(theCount, listenerActive, f)
    }

    for theCount = 1; ; theCount++ {

        if mainActive {
            fmt.Println("MAIN: accept")
            conn, err = ln.Accept()
            checkError(err, "MAIN")

            exit := false

            for !exit {
                // Set deadline
                // conn.SetDeadline(time.Now().Add(2 * time.Second))

                // Print some info
                fmt.Printf("MAIN: reading on %v from %v
", conn.LocalAddr(), conn.RemoteAddr())

                // move time
                t0 = t1

                // read from socket
                fmt.Println("MAIN: reader")

                f.Sync()
                err = binary.Read(conn, binary.LittleEndian, &myMessage)

                f.Sync()
                if err == io.EOF {
                    fmt.Println("EOF!")
                    exit = true
                    conn.Close()
                } else {
                    checkError(err, "MAIN")
                }

                // clear screen
                c := exec.Command("clear")
                c.Stdout = os.Stdout
                c.Run()

                // print received data
                fmt.Printf("MAIN: socket message received: %d, %s
", myMessage.X, myMessage.RestOfMessage)

                // calculate speed & average
                t1 = time.Now()
                tdif := t1.Sub(t0)
                speed = float64(transferSize) / tdif.Seconds() / 1000000.0 * 8.0
                speedlist[curspeed] = speed
                curspeed = curspeed + 1
                if curspeed == 10 {
                    curspeed = 0
                }
                totalspeed := 0.0
                for i := 0; i < 10; i++ {
                    totalspeed += speedlist[i]
                }
                avgspeed = totalspeed / 10

                // print speed
                fmt.Printf("MAIN: avg mbit/s %9.2f ; actual mbit/s: %9.2f
", avgspeed, speed)
                // time.Sleep(1 * time.Second)
            }
        }
    }
}

func checkError(err error, name string) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "%s: Fatal error: %s
", name, err.Error())
        //      panic(fmt.Sprintf("%v", err.Error()))
        os.Exit(1)
    }
}

Here's the stacktrace of the client when it's blocked writing:

goroutine 1 [running]:
runtime.throw(0x1927b8, 0x5)
    /usr/local/go/src/runtime/panic.go:527 +0x90 fp=0xc82004bd78 sp=0xc82004bd60
runtime.sigpanic()
    /usr/local/go/src/runtime/sigpanic_unix.go:27 +0x2ba fp=0xc82004bdc8 sp=0xc82004bd78
main.main()
    /Users/ple/dev/go/src/Peter-test/main.go:108 +0x33c fp=0xc82004bf50 sp=0xc82004bdc8
runtime.main()
    /usr/local/go/src/runtime/proc.go:111 +0x2b0 fp=0xc82004bfa0 sp=0xc82004bf50
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1696 +0x1 fp=0xc82004bfa8 sp=0xc82004bfa0

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 5 [trace reader (blocked)]:
runtime.ReadTrace(0x0, 0x0, 0x0)
    /usr/local/go/src/runtime/trace.go:339 +0x207
runtime/trace.Start.func1(0x5a42e0, 0xc82002a020)
    /usr/local/go/src/runtime/trace/trace.go:28 +0x18
created by runtime/trace.Start
    /usr/local/go/src/runtime/trace/trace.go:34 +0x78

goroutine 6 [runnable]:
reflect.Value.Index(0x1234c0, 0xc8204ac004, 0x51, 0x75, 0x12ac00, 0xc8204ac078, 0x48)
    /usr/local/go/src/reflect/value.go:823
encoding/binary.(*encoder).value(0xc8200475a0, 0x1234c0, 0xc8204ac004, 0x51)
    /usr/local/go/src/encoding/binary/binary.go:509 +0x808
encoding/binary.(*encoder).value(0xc8200475a0, 0x162ba0, 0xc8204ac000, 0x59)
    /usr/local/go/src/encoding/binary/binary.go:518 +0xb4f
encoding/binary.Write(0x621138, 0xc8200a2000, 0x621160, 0x289ef0, 0x162ba0, 0xc8204ac000, 0x0, 0x0)
    /usr/local/go/src/encoding/binary/binary.go:316 +0x1792
main.listener(0x0, 0x1, 0xc82002a020)
    /Users/ple/dev/go/src/Peter-test/main.go:59 +0xac8
created by main.main
    /Users/ple/dev/go/src/Peter-test/main.go:105 +0x332
  • 写回答

1条回答 默认 最新

  • dongpa2000 2015-09-04 20:16
    关注

    Jim's answer was right. Main goes into a busy loop. I solved it by passing a channel to listener and waiting for it at the end of main. The client "writes" to it after the for loop, which is an infinite loop, so main never ends. The program's been passing data ever since. I'll let it run overnight to be certain.

    I'm only getting about 12.5Mbit/s, which is a bit funny. Connection is 1Gbit Wifi AC to a 100mbit Ethernet switch to the Raspberry Pi. But that's another question.

    Thanks!

    评论

报告相同问题?

悬赏问题

  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法