如何在Go语言中创建客户端服务器?

4

我是一名新手,正在学习使用Go语言准备构建客户端和服务器,并尝试编写代码,但是没有输出。它没有提供任何错误信息,只是在侦听。

请有经验的人帮助我,我想使用Go创建身份验证系统,在该系统中,服务器将使用用户名密码对客户端进行身份验证。

服务器:

package main

import (
        "fmt"
        "net"
)

func main() {
        service := "0.0.0.0:8080"
        tcpAddr, err := net.ResolveTCPAddr("tcp", service)
        checkError(err)
        listener, err := net.ListenTCP("tcp", tcpAddr)
        checkError(err)
        for {
                conn, err := listener.Accept()
                //fmt.Println("Server listerning")
                _, err = conn.Read([]byte("HEAD"))
                if err != nil {
                        conn.Close()
                }
                if err != nil {
                        continue
                }
        }
}

func checkError(err error) {
        if err != nil {
                fmt.Println("Fatal error ", err.Error())
        }
}

客户端:

package main

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

func main() {
        if len(os.Args) != 2 {
                fmt.Println("Usage: ", os.Args[0], "host")
                os.Exit(1)
        }
        host := os.Args[1]
        conn, err := net.Dial("tcp", host+":8080")
        checkError(err)
        _, err = conn.Write([]byte("HEAD"))
        reader := bufio.NewReader(os.Stdin)
        for {
                line, err := reader.ReadString('\n')
                ftm.Println(err)
                line = strings.TrimRight(line, " \t\r\n")
                if err != nil {
                        conn.Close()
                        break

                }
        }
}
func checkError(err error) {
        if err != nil {
                fmt.Println("Fatal error ", err.Error())
        }
}

checkError函数基本上只是打印错误,然后什么也不做。这本身就是错误的,而且它的名称因此具有误导性。考虑使用log.Fatal(err),它会打印错误并调用os.Exit(1)。或者将这样的调用添加到您的错误处理函数中,并将其重命名为die或类似的名称。 - kostix
不要忘记,即使没有错误,在某个时候你也会想关闭你的连接。 defer conn.close() 应该在括号外部和之后,第一个错误子句应该在读取操作之前 - 我知道这是几年后了,但以防万一有人读到这篇文章。 - Jono
2个回答

5

我不确定您是否需要解析地址才能收听。

您应该可以直接进行以下操作:

listener, err := net.Listen("tcp", ":8080")

您似乎没有在服务器端使用接收到的字节(您丢弃了 Read 的结果),这就解释了为什么您认为没有接收到任何内容。

请注意,您的代码一次只能处理一个连接。您应该在新的goroutine中处理每个打开的连接。

以下是相关问题中TCP客户端-服务器通信的示例:


在进行了那个更改之后,我运行了:go run fs.go,因此它会出现错误: #命令行参数 .\fs.go:10:无法在函数参数中使用“:8080”(类型为字符串)作为* net.TCPAddr类型 - user1788542
抱歉:要使用的函数是Listen,而不是ListenTCP。我已经编辑过了。Listen在内部调用ListenTCP。 - Denys Séguret
好的,你能否给我提供除了https://dev59.com/yWgu5IYBdhLWcg3wnYPo#11202252之外的其他例子? - user1788542
3
@KarimkhanPathan,我认为上面给出的例子就是你需要的。因为你需要发送结构化数据(用户名/密码;认证结果等),而不仅仅是任意字符串,所以你需要编码器和解码器。使用编码器/解码器,你不必再处理bufio。只需使用Encode()和Decode()方法即可。如果你想与其他语言进行接口交互,而不想使用Gob,则可以简单地将Gob替换为Json、XML或其他格式。 - Song Gao
我在监听端口时犯了错误。正确的方式是在适当的位置使用以下代码:listener, err := net.Listen("tcp", ":8080")。这解决了问题。 - user1788542
显示剩余2条评论

2
我不确定你期望得到什么输出,因为在客户端中,似乎你只是读取输入而没有打印任何内容。正如@dystroy所指出的那样,服务器随后会丢弃收到的内容,只检查通信中是否有错误。
此外,看起来你的服务器应该只是一直在监听,因为你将它放在一个循环中执行这个操作。如果你查看net包的文档,它提供了一个运行服务器和客户端的示例。以下是我从中制作的一个示例,对我有效。 服务器:
ln, err := net.Listen("tcp", ":8080")
// handle error
for {
    conn, err := ln.Accept()
    // handle error
    var cmd []byte
    fmt.Fscan(conn, &cmd)
    fmt.Println("Message:", string(cmd))
}

客户端:

conn, err := net.Dial("tcp", "127.0.0.1:8080")
// handle error
fmt.Fprintf(conn, "message\n")

编辑后添加:这个程序的预期结果是你运行服务器并等待。然后在不同的终端中运行客户端,它会立即退出,但现在服务器已经打印出“Message: message”。如果您再次运行客户端,服务器将再次打印相同的消息。我在我的机器上测试了这个代码(只是添加了响应错误的代码),它按照广告所说的工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接