【问题标题】:What's the proper way to use sockets in goroutines在 goroutine 中使用套接字的正确方法是什么
【发布时间】:2019-01-12 07:53:30
【问题描述】:

我正在阅读有关 Go 语言中套接字的不同内容。是否可以在没有任何并发​​控制的情况下用于 2 个 goroutine 中进行读写?

我正在显示下面的代码,但我使用频道也失败了。

我基本上创建了一个小应用程序来拦截某个应用程序的通信协议,并在它到达我的电脑中的客户端之前从服务器替换几个字节。

为此,我有 2 个 go 例程:

从服务器读取套接字,替换一些字节并发送到客户端。

另一个是从客户端读取socket并发送到服务器。

它适用于一些消息然后崩溃。 这是我的代码和控制台输出:

***注意:在 python 中类似的实现可以正常工作。

    package main

    import (
        "fmt"
        "net"
        "sync"
        "log"
    )

    func main() {

    var wg sync.WaitGroup
    wg.Add(2)

    server := StartShard()
    client := StartClient()

    go func() {
        ShardToClient(client, server)
        wg.Done()
    }()

    go func() {
        ClientToShard(client, server)
        wg.Done()
    }()

    wg.Wait()

}

func StartClient() (net.Conn){

    servAddr := "server1.gamek.io:2593"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", servAddr)
    checkError(err)
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    checkError(err)

    return conn
}

func StartShard() (net.Conn){

    service := "localhost:2593"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
    checkError(err)
    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    conn, err := listener.Accept()
    checkError(err)

    return conn
}


func ShardToClient( client net.Conn, server net.Conn  ){

    var buf = make([]byte, 1024)
    var bufRead int
    var err error

    for {
        bufRead, err = client.Read(buf)
        checkError(err)

        if bufRead > 0 {
            if buf[0] == 0x8C{
                fmt.Println("AVOIDING REDIRECTION ...")
                buf[1] = 127;
                buf[2] = 0;
                buf[3] = 0;
                buf[4] = 1;
            }
            fmt.Printf("ShardToClient(%d): %X\n", bufRead, buf[0:bufRead])
            bufRead, _ = server.Write(buf[0:bufRead])

        }
    }
}

func ClientToShard( client net.Conn, server net.Conn  ){

    var buf = make([]byte, 1024)
    var bufRead int
    var err error

    for {
        bufRead, err = server.Read(buf)
        checkError(err)

        if bufRead > 0 {
            fmt.Printf("ClientToShard(%d): %X\n", bufRead, buf[0:bufRead])
            bufRead, err = client.Write(buf[0:bufRead])
            checkError(err)
        }
    }

}

func checkError(err error) {
    if err != nil {
        log.Fatal("fatal: %s", err)
    }
}

输出:

ClientToShard(66): 0E00A8C08067616270000000073776F720000000FF

ShardToClient(3): BD0003

ClientToShard(11): BD000B352E302E392E3000

ShardToClient(46):

A8002EFF000100015468652046690D0F723

ClientToShard(3): A00001

避免重定向 ...

ShardToClient(11): 8C7F0000010A214C8D6573

2019/01/12 14:32:45 致命:EOF

【问题讨论】:

    标签: sockets go concurrency goroutine


    【解决方案1】:

    应用程序通过调用log.Fatal 处理来自网络操作的所有错误。 log.Fatal 函数退出进程。

    日志行

    2019/01/12 14:32:45 FATAL: EOF
    

    表示对等方关闭了网络连接。应用程序通过退出来处理此错误。

    应用程序应该通过清理所有资源并退出 goroutine 来处理网络错误。例如:

    func ClientToShard( client net.Conn, server net.Conn  ){
        defer client.Close() // close network connections on return from this function
        defer server.Close()
    
        var buf = make([]byte, 1024)
        var bufRead int
        var err error
    
        for {
            bufRead, err = server.Read(buf)
            if err != nil {
                return
            }
    
            if bufRead > 0 {
                fmt.Printf("ClientToShard(%d): %X\n", bufRead, buf[0:bufRead])
                bufRead, err = client.Write(buf[0:bufRead])
                if err != nil {
                    return
                }
            }
        }
    
    }
    

    对 ShardToClient 进行类似的更改。

    额外评论:将ClientToShard 的核心替换为对io.Copy 的调用。

    【讨论】:

      【解决方案2】:

      documentation of net.Conn 说:

      多个 goroutine 可以同时调用 Conn 上的方法。

      所以我怀疑这本身不是问题,而是您的代码中存在错误。

      如果不使用分片和客户端等设置环境,很难调试代码,但我只想指出并发访问Conn 不是问题。尝试检测客户端读取更多信息 - 是否使用 EOF 读取任何数据?

      【讨论】:

        猜你喜欢
        • 2013-07-31
        • 1970-01-01
        • 1970-01-01
        • 2023-01-17
        • 2010-10-14
        • 2021-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多