ZBLOG

golang 编写 P2P文件互传

本文将介绍如何使用 Golang 编写 P2P 文件互传程序。

P2P 网络是指点对点网络,即没有中心化管理的网络。在 P2P 网络中,每个节点都可以直接与其他节点进行通信和数据交换,而不需要通过中间服务器。这种网络结构使得 P2P 网络具有高度的可靠性、强大的扩展性和灵活性。

Golang 作为一门并发编程语言,非常适合用来开发 P2P 程序。下面我们将介绍如何使用 Golang 编写一个简单的 P2P 文件互传程序。

  1. 创建 TCP Server 和 Client

首先,我们需要创建一个 TCP Server 和一个 TCP Client。Server 将监听一个端口,当有客户端连接上来时会将文件发送给客户端,而 Client 则会连接到 Server 并请求文件。

// server.go

func main() {
    listener, err := net.Listen("tcp", "127.0.0.1:10000")
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()

    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Println(err)
            continue
        }

        go func(conn net.Conn) {
            defer conn.Close()
            file, err := os.Open("file.txt")
            if err != nil {
                log.Println(err)
                return
            }
            defer file.Close()

            _, err = io.Copy(conn, file)
            if err != nil {
                log.Println(err)
                return
            }
        }(conn)
    }
}
// client.go

func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:10000")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    file, err := os.Create("file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    _, err = io.Copy(file, conn)
    if err != nil {
        log.Fatal(err)
    }
}

上面的代码中,Server 监听端口 10000,并等待客户端连接。当有客户端连接上来时,Server 会将文件 file.txt 发送给该客户端。

Client 连接到 Server 并请求文件,最终将文件保存在本地的 file.txt 文件中。

  1. 将 Client 和 Server 合并成一个程序

现在我们已经创建了一个简单的 Server 和 Client,但是这两个程序是独立的,需要手动启动和关闭。接下来,我们将它们合并成一个程序,即如果程序运行在 Server 模式下,它将监听 10000 端口并等待客户端连接;如果程序运行在 Client 模式下,它将连接到 Server 并请求文件。

// p2p.go

func main() {
    if len(os.Args) < 2 {
        log.Fatal("Usage: p2p [mode]")
    }

    mode := os.Args[1]
    if mode == "server" {
        listener, err := net.Listen("tcp", "127.0.0.1:10000")
        if err != nil {
            log.Fatal(err)
        }
        defer listener.Close()

        for {
            conn, err := listener.Accept()
            if err != nil {
                log.Println(err)
                continue
            }

            go func(conn net.Conn) {
                defer conn.Close()
                file, err := os.Open("file.txt")
                if err != nil {
                    log.Println(err)
                    return
                }
                defer file.Close()

                _, err = io.Copy(conn, file)
                if err != nil {
                    log.Println(err)
                    return
                }
            }(conn)
        }
    } else if mode == "client" {
        conn, err := net.Dial("tcp", "127.0.0.1:10000")
        if err != nil {
            log.Fatal(err)
        }
        defer conn.Close()

        file, err := os.Create("file.txt")
        if err != nil {
            log.Fatal(err)
        }
        defer file.Close()

        _, err = io.Copy(file, conn)
        if err != nil {
            log.Fatal(err)
        }
    } else {
        log.Fatal("Invalid mode")
    }
}

上面的代码中,我们使用了命令行参数来指定程序运行的模式,即 server 或 client。如果程序以 server 模式运行,它将监听 10000 端口并等待客户端连接;如果程序以 client 模式运行,它将连接到 Server 并请求文件。

  1. 使用多个节点进行 P2P 文件传输

现在我们已经创建了一个基本的 P2P 文件互传程序,但是它还有很多限制,比如只能在同一台机器上运行,不能扩展到多个节点上。

为了实现多节点 P2P 文件传输,我们需要让每个节点既可以作为 Server 也可以作为 Client。当一个节点收到其他节点的请求时,它会将文件传输给该节点;当一个节点需要文件时,它会连接到其他节点并请求文件。

下面是一个简单的实例,其中有三个节点 A、B、C,它们都运行在本地,监听不同的端口。

// node.go

func main() {
    if len(os.Args) < 3 {
        log.Fatal("Usage: node [port] [peer1] [peer2] ...")
    }

    port := os.Args[1]
    peers := os.Args[2:]

    listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%s", port))
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()

    log.Printf("Node %s started\n", port)

    go func() {
        for {
            conn, err := listener.Accept()
            if err != nil {
                log.Println(err)
                continue
            }

            go func(conn net.Conn) {
                defer conn.Close()
                file, err := os.Open("file.txt")
                if err != nil {
                    log.Println(err)
                    return
                }
                defer file.Close()

                _, err = io.Copy(conn, file)
                if err != nil {
                    log.Println(err)
                    return
                }
            }(conn)
        }
    }()

    for _, peer := range peers {
        go func(peer string) {
            conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%s", peer))
            if err != nil {
                log.Printf("Node %s connect to %s failed: %s\n", port, peer, err)
                return
            }
            defer conn.Close()

            file, err := os.Create(fmt.Sprintf("file-%s.txt", peer))
            if err != nil {
                log.Printf("Node %s create file for %s failed: %s\n", port, peer, err)
                return
            }
            defer file.Close()

            _, err = io.Copy(file, conn)
            if err != nil {
                log.Printf("Node %s receive file from %s failed: %s\n", port, peer, err)
                return
            }

            log.Printf("Node %s receive file from %s success\n", port, peer)
        }(peer)
    }

    select {}
}

在上面的代码中,每个节点都需要指定一个端口号和一些其他节点的地址。当一个节点接收到其他节点的请求时,它将文件发送给该节点;当一个节点需要文件时,它将连接到其他节点并请求文件。

在这个简单的示例中,我们使用了 select {} 来让程序永远运行下去,这是一个阻塞语句,可以保证程序不会退出。

  1. 总结

本文介绍了如何使用 Golang 编写 P2P 文件互传程序。我们首先创建了一个简单的 TCP Server 和 Client,然后将它们合并成一个程序。最后,我们使用多个节点进行 P2P 文件传输,并实现了对等节点之间的文件传输。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=2399

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?