为了账号安全,请及时绑定邮箱和手机立即绑定

客户端无法将数据发送到 golang 中的 TCP 服务器?

客户端无法将数据发送到 golang 中的 TCP 服务器?

Go
不负相思意 2023-06-12 15:36:21
我有 TCP 服务器和客户端,简单 TCP 服务器将只接收传入数据并打印它,客户端将不断创建套接字连接并在循环中将数据发送到 TCP 服务器。我得到的信息是,如果 TCP 连接正确关闭,这个过程应该继续进行而不会出现任何崩溃。但是在从客户端接收到服务器的一些数据后,客户端因错误而崩溃total times data send: 16373panic: runtime error: invalid memory address or nil pointer dereference[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10d7594]goroutine 1 [running]:main.sendData()/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:178 +0xb4main.main()/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:170 +0x2aexit status 2服务器.gopackage mainimport (    "bufio"    "fmt"    "net"    "sync")var wg sync.WaitGroupvar count = 0var timeX string = ""var connQueue = make(chan string)func main() {    tcpListner := startTCPConnection()    incomingTCPListener(tcpListner)}//startTCPConnectionfunc startTCPConnection() net.Listener {    tcpListner, tcpConnectonError := net.Listen("tcp", "localhost:3000")    if tcpConnectonError != nil {        print(tcpConnectonError)        return     }    return tcpListner}//incomingTCPListenerfunc incomingTCPListener(tcpListner net.Listener) {    for {        incomingConnection, incomingConnectionError := tcpListner.Accept()        if incomingConnectionError != nil {            print(incomingConnectionError)            return        }        wg.Add(1)        go processIncomingRequest(incomingConnection)        wg.Wait()    }}//processIncomingRequestfunc processIncomingRequest(connection net.Conn) {    defer connection.Close()    var scanner = bufio.NewScanner(connection)    var blob = ""    for scanner.Scan() {        fmt.Println("sadd")        text := scanner.Text()        blob += text    }    print(blob)    count++    fmt.Println("totalCount", count)    wg.Done()}有什么办法可以避免这种崩溃,让它一直运行下去吗? 我是 Go 的新手,所以如果我犯了任何愚蠢的错误,我很抱歉。
查看完整描述

3 回答

?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

首先,如果你想打印到 stderr,(即你的打印调用),我建议使用 fmt 库


fmt.Fprintln(os.Stderr, "hello world")

为什么:因为打印功能不能保证留在语言中。1个


其次,通常的做法是将错误名称命名为err,而不必将错误拼写为tcpConnectionError.


connection, connectionError := net.Dial("tcp", "localhost:3000")第三,由于您在服务器中使用 tcp,因此正在侦听 ipv6 和 ipv4。我至少在 Windows 机器上观察到连接打开两个连接,一个用于 ipv4 和 ipv6,然后丢弃 ipv6 连接以支持 ipv4。


最后,当 TCP 连接关闭时,端口不能立即重新使用,因为操作系统必须等待 TIME_WAIT 间隔(最大段生存期,MSL)的持续时间。

您的客户端代码正在打开大量非常短暂的 tcp 连接,并且根据您临时端口范围的范围,您的代码可能会或可能不会崩溃。从16373的数量来看,你有默认范围。2个


>> sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last

net.inet.ip.portrange.first: 49152

net.inet.ip.portrange.last: 65535

最后,


如果您想避免因端口用完而导致崩溃:

1. 增加端口的临时范围

2. 使用 Docker,容器在它们自己的网络上,因此使用一组不同的端口绕过有限的端口范围。

3. 在您的客户端代码中引入一个自动收报机,以模拟每 x 秒/分钟的连接


package main


import (

    "fmt"

    "net"

    "time"

)


var count = 0


func testJSON2() string {

    return `Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.`

}


func main() {

    max := 1000


    timer1 := time.NewTicker(5 * time.Second)


    i := 0

    for range timer1.C {

        sendData()

        if i == max {

            timer1.Stop()

        }

        i++

    }

}


func sendData() {


    connection, connectionError := net.Dial("tcp", "localhost:3000")

    fmt.Println(connection.LocalAddr())


    if connectionError != nil {

        fmt.Println(connectionError)

        return

    }

    newmessage := testJSON2()

    connection.Write([]byte(newmessage + "\n"))

    count++

    fmt.Println(count)


    err := connection.Close()

    if err != nil {

        fmt.Println(err)

    }

}


查看完整回答
反对 回复 2023-06-12
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

if connectionError != nil {

        fmt.Println(connectionError)

        return 

    }

defer connection.Close()

defer connection.Close() 应该在错误检查之后,因为连接变量可以是 nil incase 拨号返回时出现一些错误。


查看完整回答
反对 回复 2023-06-12
?
暮色呼如

TA贡献1853条经验 获得超9个赞

package main


import (

    "bufio"

    "fmt"

    "net"

    "sync"

)


var wg sync.WaitGroup

var count = 0

var timeX string = ""


var connQueue = make(chan string)


func main() {

    tcpListner := startTCPConnection()

    incomingTCPListener(tcpListner)

    wg.Wait()

}


//startTCPConnection

func startTCPConnection() net.Listener {

    tcpListner, tcpConnectonError := net.Listen("tcp", "localhost:3000")

    if tcpConnectonError != nil {

        print(tcpConnectonError)

        // return 

        log.Fatal(tcpConnectonError)

    }

    return tcpListner

}


//incomingTCPListener

func incomingTCPListener(tcpListner net.Listener) {


    for {

        incomingConnection, incomingConnectionError := tcpListner.Accept()

        if incomingConnectionError != nil {

            print(incomingConnectionError)

            return

        }

        wg.Add(1)

        go processIncomingRequest(incomingConnection)

        // wg.Wait()

    }

}


//processIncomingRequest

func processIncomingRequest(connection net.Conn) {


    defer connection.Close()


    var scanner = bufio.NewScanner(connection)


    var blob = ""

    for scanner.Scan() {

        fmt.Println("sadd")

        text := scanner.Text()

        blob += text

    }

    print(blob)

    count++

    fmt.Println("totalCount", count)

    wg.Done()

}


问题出在server.go。我的猜测是您通过在 incomingTCPListener() 函数中调用 wg.Wait() 而不是 main() 来耗尽端口。此外,在 startTCPConnection() 函数中直接返回将导致编译器错误。


查看完整回答
反对 回复 2023-06-12
  • 3 回答
  • 0 关注
  • 87 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信