Как правильно использовать сокеты в goroutines? - PullRequest
0 голосов
/ 12 января 2019

Я читаю разные вещи о сокетах в Go lang. Можно ли использовать его в 2-х программах для чтения и записи без какого-либо контроля параллелизма?

Я показываю код ниже, но я также не смог использовать каналы.

Я в основном создал небольшое приложение для перехвата протокола связи определенного приложения, и я заменяю несколько байтов с сервера, прежде чем он попадет в клиент моего компьютера.

для этого у меня есть 2 процедуры:

Одно чтение сокета с сервера, замена некоторых байтов и отправка клиенту.

Другой читает сокет с клиента и отправляет на сервер.

отлично работает для нескольких сообщений, затем вылетает. Это мой код и вывод на консоль:

*** Примечание: аналогичная реализация в 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 FATAL: EOF

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Приложение обрабатывает все ошибки сетевых операций, вызывая log.Fatal. Функция log.Fatal завершает процесс.

Бревно

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

означает, что узел закрыл сетевое соединение. Приложение обработало эту ошибку путем выхода.

Приложение должно обрабатывать сетевые ошибки, очищая любые ресурсы и выходя из программы. Например:

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 .

0 голосов
/ 12 января 2019

В документации net.Conn говорится:

Несколько процедур могут вызывать методы на Conn одновременно.

Так что я подозреваю, что это не проблема сама по себе, а скорее у вас есть ошибка в вашем коде.

Трудно отладить ваш код без настройки env с помощью шарда, клиента и т. Д., Но я просто хочу отметить, что параллельный доступ к Conn не является проблемой. Попробуйте дать клиенту дополнительную информацию - есть ли данные, прочитанные с помощью EOF?

...