新的尝试使TCP服务器并发。我找到了包括这一个在内的多个例子,但我想弄清楚为什么我对非并发版本所做的一些更改不起作用。
这是我从下面开始的原始示例代码
package main
import "bufio"
import "fmt"
import "log"
import "net"
import "strings" // only needed below for sample processing
func main() {
fmt.Println("Launching server...")
fmt.Println("Listen on port")
ln, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}
defer ln.Close()
fmt.Println("Accept connection on port")
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Println("Entering loop")
// run loop forever (or until ctrl-c)
for {
// will listen for message to process ending in newline (\n)
message, _ := bufio.NewReader(conn).ReadString('\n')
// 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 + "\n"))
}
}上面的方法是可行的,但并不是并行的。
这是我修改后的代码
package main
import "bufio"
import "fmt"
import "log"
import "net"
import "strings" // only needed below for sample processing
func handleConnection(conn net.Conn) {
fmt.Println("Inside function")
// run loop forever (or until ctrl-c)
for {
fmt.Println("Inside loop")
// will listen for message to process ending in newline (\n)
message, _ := bufio.NewReader(conn).ReadString('\n')
// 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 + "\n"))
}
}
func main() {
fmt.Println("Launching server...")
fmt.Println("Listen on port")
ln, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}
//defer ln.Close()
fmt.Println("Accept connection on port")
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Println("Calling handleConnection")
go handleConnection(conn)
}我的代码是基于其他几个关于并发服务器的例子,但是当我运行上面的服务器时,服务器似乎退出了,而不是运行handleConnection函数。
发射服务器..。 监听端口 接受端口连接 调用handleConnection
希望得到任何类似的反馈,我使用相同的方法找到并测试了类似的代码示例,同时调用函数来处理连接,工作正常;因此,我想知道修改后的代码与我看到的其他示例有什么不同,因为它们对我来说似乎是一样的。
我不知道是否是问题,但我试着评论推迟电话关闭。这没什么用。
谢谢。
发布于 2018-07-09 22:02:03
您的main函数在接受新连接后立即返回,因此程序在处理连接之前就会退出。由于您可能还希望接收多个单独的连接(否则就没有并发性),所以应该将其放入for循环中。
您还将在for循环的每次迭代中创建一个新的缓冲读取器,这将丢弃任何缓冲的数据。您需要在for循环之外这样做,我在这里演示了创建一个新的bufio.Scanner,它是读取换行符分隔文本的一种更简单的方法。
import (
"bufio"
"fmt"
"log"
"net"
"strings"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
message := scanner.Text()
fmt.Println("Message Received:", message)
newMessage := strings.ToUpper(message)
conn.Write([]byte(newMessage + "\n"))
}
if err := scanner.Err(); err != nil {
fmt.Println("error:", err)
}
}
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}
fmt.Println("Accept connection on port")
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Println("Calling handleConnection")
go handleConnection(conn)
}
}发布于 2018-07-09 21:59:39
看到这种行为的原因是,即使go例程仍在运行,主方法也会退出。一定要阻止主要的方法来达到你想要达到的目标。
主要可以添加这样的内容:
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c // This will block until you manually exists with CRl-C你也可以把你的推迟时间
发布于 2018-07-10 00:43:03
当您使用go func()语法运行函数时,您正在执行一个新的goroutine,而不阻塞主函数。但是,当主goroutine完成时,程序将退出,因此简而言之,只要您希望您的子goroutine执行,就需要阻塞主goroutine。
我经常发现自己在go标准库中如何解决类似的问题。例如,来自Server.Serve()包的http做了类似的事情。以下是摘录的版本(缩短,请按链接查看完整版本):
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
ctx := context.Background()
for {
rw, e := l.Accept()
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
// handle the error
}
return e
}
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}为了停止上述功能,我们可以关闭侦听器(例如,通过中断信号),这反过来会在Accept()上产生一个错误。上面的实现检查serv.GetDoneChan()通道是否返回一个值,作为错误预期和服务器关闭的指示符。
https://stackoverflow.com/questions/51254367
复制相似问题