【问题标题】:How to build a server which can receive and send message to multiple client using Go?如何使用 Go 构建一个可以接收和发送消息到多个客户端的服务器?
【发布时间】:2018-10-04 04:04:20
【问题描述】:

我是 Go 新手,我正在尝试创建一个服务器,该服务器可以接收来自客户端的消息并将其发送到其他客户端或任何其他特定客户端。我尝试了很多聊天示例,但我想做的是创建两个文件,一个用于服务器,另一个用于客户端。这是我目前尝试的代码。

server.go

package main

import "net"
import "fmt"
import "bufio"
import "strings" 

func send(c net.Conn){
    netData, err := bufio.NewReader(c).ReadString('\n')
            if err != nil {
                    fmt.Println(err)
                    return
            }

    temp := strings.TrimSpace(string(netData))
    fmt.Printf(temp)        

}

func main() {

    fmt.Println("Launching server...")

    // listen on all interfaces
    ln, _ := net.Listen("tcp", ":8081")

    for {
        // Listen for an incoming connection.
        conn, err := ln.Accept()

        if err != nil {
            fmt.Println("Error accepting: ", err.Error())
            continue
        }

        go send(conn)

    } 

client.go

package main

import "net"
import "fmt"
import "bufio"
import "os"

func recieve(conn net.Conn){
    message, _ := bufio.NewReader(conn).ReadString('\n')
    fmt.Println(message)
}

func send(conn net.Conn){
    reader := bufio.NewReader(os.Stdin)

    text, _ := reader.ReadString('\n')
    fmt.Fprintf(conn, text)
}


func main(){

    // connect to this socket
    conn, err := net.Dial("tcp", "127.0.0.1:8081")
    if err != nil {
        fmt.Println("Error accepting: ", err.Error())

    }

    for {
        go recieve(conn)
        go send(conn)  
    }
    conn.Close()
}

当我尝试运行时,我的计算机崩溃了。我知道我在处理发送和接收的消息时犯了一些错误,但无法弄清楚。我将不胜感激任何帮助。谢谢。

【问题讨论】:

  • 它是如何崩溃的,这两个程序的输出是什么?
  • 第一次接受多个客户端的输入。之后,它没有任何输入,几秒钟后,整个计算机崩溃了。我从任务管理器中检查了它正在高度使用处理器。

标签: go server client


【解决方案1】:

我已将您的代码修改为如下所示。虽然它似乎工作 它有点原始,缺乏适当的错误处理。

server.go

package main

import (
    "bufio"
    "fmt"
    "io"
    "net"
    "strings"
)

func (s *server) recvAndEcho(c io.ReadCloser) {
    defer c.Close()

    for {
        netData, err := bufio.NewReader(c).ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return
        }

        temp := strings.TrimSpace(string(netData))
        fmt.Println(temp)
        s.broadcastMsg(netData)
    }
}

type server struct {
    clients []io.Writer
}

func (s *server) addClient(c net.Conn) {
    s.clients = append(s.clients, c)
}

func (s *server) broadcastMsg(msg string) {
    for _, cl := range s.clients {
        // Send the original msg back to the client
        _, err := cl.Write([]byte(fmt.Sprintf("server replied: %s\n", msg)))
        if err != nil {
            fmt.Println("server: failed to write!")
        }
    }
}

func main() {
    fmt.Println("Launching server...")
    srv := &server{}

    // listen on all interfaces
    ln, _ := net.Listen("tcp", ":8081")

    for {
        // Listen for an incoming connection.
        conn, err := ln.Accept()

        if err != nil {
            fmt.Println("Error accepting: ", err.Error())
            continue
        }
        srv.addClient(conn)
        go srv.recvAndEcho(conn)
    }
}

client.go

package main

import (
    "bufio"
    "fmt"
    "io"
    "net"
    "os"
)

func recvLoop(r io.Reader) {
    var inbuf [64]byte
    for {
        n, err := r.Read(inbuf[:])
        if err != nil {
            fmt.Println("Failed to receive msg from the server!")
            break
        }
        fmt.Print(string(inbuf[:n]))
    }
}

func main() {
    // connect to this socket
    conn, err := net.Dial("tcp", "127.0.0.1:8081")
    if err != nil {
        fmt.Println("Error accepting: ", err.Error())
        return

    }

    sc := bufio.NewScanner(os.Stdin)
    rd := bufio.NewReader(conn)
    go recvLoop(rd)

    for sc.Scan() {
        if sc.Err() != nil {
            fmt.Println("scanner error!")
        }
        txt := sc.Text()
        // It is important to append "newline" here because you are
        // using the "ReadString('\n')" method on the server side.
        // Otherwise, the program would stuck at the "readstring"
        // method.
        b := []byte(txt + "\n")
        _, err := conn.Write(b)
        if err != nil {
            fmt.Println("Failed to send data to the server!")
            break
        }
    }

    conn.Close()
}

【讨论】:

  • 您好,非常感谢您的回复。我想要做的是服务器应该将消息回复给所有客户端或者可能是特定客户端(而不是发送消息的客户端)。如何添加该方法?
  • 好的,我已更改代码以向所有连接的客户端发送消息。我希望它对你有用。
  • 非常感谢。有用。但似乎每个客户端都必须提供一些输入或按 Enter 键才能获取广播消息。我应该在客户端添加一个新的 goroutine 函数来即时接收和打印消息吗?
  • 你确定吗?因为它不应该期望按下任何键来打印来自服务器的消息。看看 recvLoop 函数。
  • 是的,客户端必须输入或输入才能接收消息。我想我想通了。我正在发布我在客户端添加的修改后的代码。
【解决方案2】:

我以这种方式修改了客户端。在 main 函数中调用 goroutine 函数“receive”。

package main

import (
"bufio"
"fmt"
"net"
"os"
)

func main() {
// connect to this socket
conn, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
    fmt.Println("Error accepting: ", err.Error())

}
go receive(conn)
sc := bufio.NewScanner(os.Stdin)


for sc.Scan() {
    if sc.Err() != nil {
        fmt.Println("scanner error!")
    }
    txt := sc.Text()
    // It is important to append "newline" here because you are
    // using the "ReadString('\n')" method on the server side.
    // Otherwise, the program would stuck at the "readstring"
    // method.
    b := []byte(txt + "\n")
    _, err := conn.Write(b)
    if err != nil {
        fmt.Println("Failed to send data to the server!")
        break
    }


}

conn.Close()
}

func receive(c net.Conn){
    rd := bufio.NewReader(c)
    var inbuf [64]byte
for{
 n, err := rd.Read(inbuf[:])

if err != nil {
        fmt.Println("Failed to receive msg from the server!")
        break
    }
    fmt.Print(string(inbuf[:n]))

}
c.Close()
}

【讨论】:

    猜你喜欢
    • 2021-12-04
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    相关资源
    最近更新 更多