首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使Golang服务器并发

使Golang服务器并发
EN

Stack Overflow用户
提问于 2018-07-09 21:37:16
回答 4查看 12.2K关注 0票数 9

新的尝试使TCP服务器并发。我找到了包括这一个在内的多个例子,但我想弄清楚为什么我对非并发版本所做的一些更改不起作用。

这是我从下面开始的原始示例代码

代码语言:javascript
复制
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"))
  }
}

上面的方法是可行的,但并不是并行的。

这是我修改后的代码

代码语言:javascript
复制
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

希望得到任何类似的反馈,我使用相同的方法找到并测试了类似的代码示例,同时调用函数来处理连接,工作正常;因此,我想知道修改后的代码与我看到的其他示例有什么不同,因为它们对我来说似乎是一样的。

我不知道是否是问题,但我试着评论推迟电话关闭。这没什么用。

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-07-09 22:02:03

您的main函数在接受新连接后立即返回,因此程序在处理连接之前就会退出。由于您可能还希望接收多个单独的连接(否则就没有并发性),所以应该将其放入for循环中。

您还将在for循环的每次迭代中创建一个新的缓冲读取器,这将丢弃任何缓冲的数据。您需要在for循环之外这样做,我在这里演示了创建一个新的bufio.Scanner,它是读取换行符分隔文本的一种更简单的方法。

代码语言:javascript
复制
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)
    }
}
票数 11
EN

Stack Overflow用户

发布于 2018-07-09 21:59:39

看到这种行为的原因是,即使go例程仍在运行,主方法也会退出。一定要阻止主要的方法来达到你想要达到的目标。

主要可以添加这样的内容:

代码语言:javascript
复制
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c // This will block until you manually exists with CRl-C

你也可以把你的推迟时间

票数 4
EN

Stack Overflow用户

发布于 2018-07-10 00:43:03

当您使用go func()语法运行函数时,您正在执行一个新的goroutine,而不阻塞主函数。但是,当主goroutine完成时,程序将退出,因此简而言之,只要您希望您的子goroutine执行,就需要阻塞主goroutine。

我经常发现自己在go标准库中如何解决类似的问题。例如,来自Server.Serve()包的http做了类似的事情。以下是摘录的版本(缩短,请按链接查看完整版本):

代码语言:javascript
复制
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()通道是否返回一个值,作为错误预期和服务器关闭的指示符。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51254367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档