创建服务器并连接到它

I'm trying to create a server and connect to it in Go but when the server starts running, no functions after it are called because the function that starts the server appears to be blocking. I tried using a goroutine to run the server in the background so that other code can be executed but that's not really working either. I'm getting an error that I don't understand

panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x496757]

Here is my code for the server

func RunServer(port string) {

    fmt.Println("Launching server...")
    ln, err := net.Listen("tcp", port)
    conn, _ := ln.Accept()

    // run loop forever (or until ctrl-c)
    for {

        // will listen for message to process ending in newline (
)
        message, _ := bufio.NewReader(conn).ReadString('
')

        // output message received
        fmt.Print("Message Received:", string(message))

        // sample process for string received
        newmessage := strings.ToUpper(message)

        // send new string back to client
        conn.Write([]byte(newmessage + "
"))
    }
}

And here is the code for the client.

func createInitalClient(port int) {

    // run server then create a client that connects to it
    portToRunOn := fmt.Sprintf("%s%d", ":", port)
    go RunServer(portToRunOn)
}

func main() {

    createInitalClient(5000)

    // connect to this socket
    conn, _ := net.Dial("tcp", "127.0.0.1:5000")

    for {
        // read in input from stdin

        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text to send: ")
        text, _ := reader.ReadString('
')

        // send to socket
        fmt.Fprintf(conn, text+"
")

        // listen for reply
        message, _ := bufio.NewReader(conn).ReadString('
')
        fmt.Print("Message from server: " + message)
    }
}

Am I doing this right or is there another approach to do what I'm trying to do? I'm a little hesistant to use goroutines because introducing async behavior might be wrong in my case.

EDIT 1: looks like this error is happening because the client is trying to connect to the server before it starts.

EDIT 2: I (might have) fixed this by adding a boolean channel in the server that returns true right before the listeners starts accepting connections. Then the client only connects to the server if the value coming from the channel is true. I'm not sure if this is the correct fix in this scenario but it appears to be working.

dongmu5920
dongmu5920 如果您一直在检查错误,您将收到此拨号tcp127.0.0.1:5000:getsockopt:连接被拒绝,这会立即告诉您问题出在哪里。
大约 2 年之前 回复
dpsx99068
dpsx99068 永远不要忽略错误返回值。
大约 2 年之前 回复

1个回答



您的服务器是在goroutine中启动的,该例程由Go运行时异步生成,并且需要一些时间来计划和执行。 具体来说,运行时不会在继续执行 main </ code>函数之前等待服务器goroutine启动。</ p>

您要么需要:</ p> \ n


  • 安排服务器goroutine在服务器准备好接受连接时进行通信–为此使用通道是一种可接受的机制; 或</ li>
  • 让您的客户端连接尝试重复连接,直到接受连接为止–实际上是轮询服务器的就绪状态。 例如:</ p>

      //预声明“ conn”以确保它保留在循环范围之外
    var conn net.Conn

    for {
    var err error
    conn,err = net.Dial(“ tcp”,“ 127.0.0.1:5000")

    //连接失败,请稍后再试。
    // TODO:在放弃前限制尝试次数。

    if err!= nil {
    time.Sleep(time.Second)
    Continue
    }

    //连接成功。 继续。
    中断
    }

    //使用“ conn”
    </ code> </ pre> </ li>
    </ ul>



    \ n

    错误值</ h2>

    如对您的问题的注释中所述,您的代码将在多个位置忽略错误值。</ p>

    请不要 在实际的生产代码中执行此操作。 返回错误是有原因的,并且可能表明代码外部存在问题,导致您的程序无法正常继续执行。 您需要检查错误值,并在返回错误值时采取适当的措施。 如果返回的 error </ code>不是 nil </ code>,则从函数调用返回的其他值(尤其是标准库中的所有值)不太可能有意义。</ p>

    是的,您最终会写很多 if err!= nil </ code>。 这是预料之中的,在某些情况下可以采用多种模式来避免使代码看起来过于重复。</ p>
    </ div>

展开原文

原文

Your server is started in a goroutine, which is spawned asynchronously by the Go runtime and will take some time to be scheduled and executed. Specifically, the runtime will not wait for the server goroutine to be started before continuing execution of the main function.

You either need to:

  • arrange for the server goroutine to communicate when the server is ready to accept connections – use of a channel is an acceptable mechanism for this; or
  • have your client connection attempt to connect repeatedly until the connection is accepted – in effect polling the server's readiness state. For example:

    // Predeclare "conn" to ensure it remains in scope outside the loop
    var conn net.Conn
    
    for {
        var err error
        conn, err = net.Dial("tcp", "127.0.0.1:5000")
    
        // Failed connection, try again in a second.
        // TODO: limit the number of attempts before giving up.
        if err != nil {
            time.Sleep(time.Second)
            continue
        }
    
        // Connected successfully. Continue.
        break
    }
    
    // do something with "conn"
    

Error values

As noted in a comment to your question, your code ignores error values in several places.

Please don't do this in real production code. Errors are returned for a reason, and may indicate a problem external to your code which prevents your program from properly continuing execution. You need to check for error values and take appropriate action where they are returned. The other value(s) returned from a function call, especially anything in the standard library, are unlikely to be meaningful if the returned error is not nil.

Yes, you end up writing if err != nil a lot. That's expected, and there are various patterns you can employ in some cases to avoid making your code seem excessively repetitive.

douyujun0152
douyujun0152 好点子。 更新了代码。
大约 2 年之前 回复
dounao5856
dounao5856 conn必须在此循环外手动声明,否则在建立连接时它将超出范围。
大约 2 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐