我正在Go中编写TCP服务器和客户端,这是一个熟悉这种语言的工作示例。我想编写一个服务器,让我们称之为MyServer,它执行以下操作 - 它有一个后端TCP服务器,它监听传入的消息,但它也有一个允许他独立发送其他消息的客户端。但是,我不知道如何告诉MyServer“在后台”听,而不会阻塞主线程。这是我的TCPServer的代码:
package main
import (
"fmt"
"net"
"os"
)
func main() {
startListener()
doOtherThins()
}
func startListener() {
listener, err := net.Listen("tcp", "localhost:9998")
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
defer listener.Close()
fmt.Println("Listening on " + "localhost:9998")
for {
// Listen for an incoming connection.
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error during accepting: ", err.Error())
os.Exit(1)
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
buf := make([]byte, 1024)
_, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading:", err.Error())
}
conn.Write([]byte("Message correctly received."))
conn.Close()
}
函数startListener()
阻塞主函数,因此只要服务器正在侦听,函数doOtherThins()
(我想独立地将数据包发送到其他服务器)就不会被触发。我试图改变主要功能并使用goroutine:
func main() {
go startListener()
doOtherThins()
}
但是服务器没有侦听传入的数据包(只是触发doOtherThins()
并结束main()
)。
是否有可能在后台旋转监听器,以允许主线程执行其他操作?
答案 0 :(得分:1)
你的最后一个例子应该做你想要的,问题是主线程在你做任何事情之前就结束了。有两个解决方案在另一个goroutine上启动doOtherThins()
,然后调用startListener()
阻止但另一个goroutine已经在运行:
func main() {
go doOtherThins()
startListener()
}
或者使用waitGroups等待代码结束,然后退出。
答案 1 :(得分:0)
以下是使用频道实现此目标的更简洁方法。
package main
import (
"net/http"
"fmt"
)
func main() {
// Create a channel to synchronize goroutines
finish := make(chan bool)
server8001 := http.NewServeMux()
server8001.HandleFunc("/foo", foo8001)
server8001.HandleFunc("/bar", bar8001)
go func() {
http.ListenAndServe(":8001", server8001)
}()
go func() {
//do other things in a separate routine
fmt.Println("doing some work")
// you can also start a new server on a different port here
}()
// do other things in the main routine
<-finish //wait for all the routines to finish
}
func foo8001(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Listening on 8001: foo "))
}
func bar8001(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Listening on 8001: bar "))
}
答案 2 :(得分:0)
添加Anuruddha答案的另一种变体
package main
import (
"io"
"net/http"
"os"
"time"
)
func main() {
server8001 := http.NewServeMux()
server8001.HandleFunc("/foo", foo8001)
server8001.HandleFunc("/bar", bar8001)
unblock(func() error {
return http.ListenAndServe(":8001", server8001)
})//forgot err check, must be done!
res, err := http.Get("http://0.0.0.0:8001/foo")
if err != nil {
panic(err)
}
defer res.Body.Close()
io.Copy(os.Stdout, res.Body)
os.Exit(0)
}
func unblock(h func() error) error {
w := make(chan error)
go func() {
w <- h()
}()
select {
case err := <-w:
return err
case <-time.After(time.Millisecond * 50):
return nil
}
}
func foo8001(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Listening on 8001: foo "))
}
func bar8001(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Listening on 8001: bar "))
}