为什么 net.Conn.close() 看起来在错误的时间关闭连接?

huangapple go评论63阅读模式
英文:

Why does net.Conn.close() seem to be closing at the wrong time?

问题

我正在尝试从TCP客户端读取和写入一些命令。我希望在最后一个函数执行完毕后关闭连接,但由于某种原因,即使明确放置在函数之后,似乎服务器在函数执行过程中断开了连接。

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
	"time"
)



func main() {
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
		}
		go handleConn(conn)
		conn.Close()
	}

}

func handleConn(someconnection net.Conn) {
	func1(someconnection)
	func2(someconnection) //在执行此部分时连接中断
}

func func2(someconnection net.Conn) {

	//发送消息(字符串)
	_, err := io.WriteString(someconnection, dosomething)
	if err != nil {
		log.Fatal(err)
	}
	//等待回复
	//发送另一条消息
	_, err = io.WriteString(someconnection, dosomething)
	if err != nil {
		log.Fatal(err)
	}
	//等待回复

	//发送另一条消息,连接往往在这里关闭
	_, err = io.WriteString(someconnection, dosomething)
	if err != nil {
		log.Fatal(err)
	}

	//等待,发送
	_, err = io.WriteString(someconnection, dosomething)
	if err != nil {
		log.Fatal(err)
	}

	//等待,读取并打印消息
	c := bufio.NewReader(someconnection)
	buff1 := make([]byte, maxclientmessagelength)
	buff1, err = c.ReadBytes(delimiter)

	fmt.Printf("\n%s\n", buff1)

	_, err = io.WriteString(someconnection, dosomething)
	if err != nil {
		log.Fatal(err)
	}
}

这意味着试图进行反向通信的客户端无法进行通信,但程序会一直运行到结束。

更新1:

通过将延迟关闭语句放置在获取连接时,取得了一些进展。

func main() {
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
		}
		defer conn.Close()
		go handleConn(conn)
	}
}

现在它不一定会在我希望关闭的那一秒内关闭,但至少现在它可以完整运行到结束。

英文:

I'm trying to read and write some commands from a TCP client. I want to close a connection after the last function has been executed but for some reason, it seems like the server disconnects the connection in the middle of the function even when explicitly placed afterward.

    package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"strconv"
"strings"
"time"
)
func main() {
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
}
go handleConn(conn)
conn.Close()
}
}
func handleConn(someconnection net.Conn) {
func1(someconnection)
func2(someconnection) //connection drops in the middle of executing this part
}
func func2(someconnection net.Conn) {
//send message(a string)
_, err := io.WriteString(someconnection, dosomething)
if err != nil {
log.Fatal(err)
}
//await reply
//send another message
_, err = io.WriteString(someconnection, dosomething)
if err != nil {
log.Fatal(err)
}
//await reply
//send another message, connection tends to close somewhere here
_, err = io.WriteString(someconnection, dosomething)
if err != nil {
log.Fatal(err)
}
//await,send
_, err = io.WriteString(someconnection, do something)
if err != nil {
log.Fatal(err)
}
//await, read and print message
c := bufio.NewReader(someconnection)
buff1 := make([]byte, maxclientmessagelength)
buff1, err = c.ReadBytes(delimiter)
fmt.Printf("\n%s\n", buff1)
_, err = io.WriteString(someconnection, dosomething)
if err != nil {
log.Fatal(err)
}
}

That means the client trying to communicate backward simply isn't able to communicate but the program runs to the end.

Update 1:

Made some progress by placing the deferred close statement to when the connection was first acquired.

func main() {
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
}
defer conn.Close()
go handleConn(conn)
}}

Now it doesn't necessarily close within the second I hope it to close but at least it now runs all the way through.

答案1

得分: 2

Goroutines是异步的,所以在这里调用handleConn之后:

go handleConn(conn)
conn.Close()

主函数会继续执行并关闭连接。
尝试正常调用handleConn函数(不使用go)。

英文:

Goroutines are asynchronous so after calling handleConn here:

go handleConn(conn)
conn.Close()

the main function continues to execute and closes the connection.
Try just calling the handleConn function regularly (without the go).

答案2

得分: 1

conn.Close 需要在 handleConn 完成其工作之后执行。你可以使用通道将其传递回主线程,但这会过于复杂(还会阻塞主线程的执行)。以下是正确的做法:

func main() {
    listener, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
        }
        go handleConn(conn)
        // 移除下面这行代码
        // conn.Close()
    }
}

handleConn 函数内部添加 conn.Close

func handleConn(someconnection net.Conn) {
    // 在下面添加这行代码
    defer someconnection.Close()
    func1(someconnection)
    func2(someconnection)
}

这样可以确保在 func1func2 执行完毕后再调用 conn.Close

英文:

The conn.Close needs to de done AFTER handleConn has done its work. You could communicate the back to the main thread using channels but that would be too complex (and also block execution of main thread). This is how it should be done

func main() {
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
}
go handleConn(conn)
// REMOVE BELOW LINE
// conn.Close()
}
}

Add conn.Close inside handleConn

func handleConn(someconnection net.Conn) {
// ADD BELOW LINE
defer someconnection.Close()
func1(someconnection)
func2(someconnection)
}

This makes sure conn.Close is called AFTER func1 and func2 are done executing

huangapple
  • 本文由 发表于 2022年4月23日 03:29:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/71973753.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定