Не удается получить правильное пробивание UDP. Ошибка: recvfrom: соединение отказано - PullRequest
1 голос
/ 12 октября 2019

Я пытаюсь соединить двух пиров за одним и тем же NAT, используя UDP дырокол , но каждый раз, когда 1 клиент отправляет пакет UDP другому клиенту, он получает ошибку:

read udp4 192.168.0.xx:xx->192.168.0.xx:xx: recvfrom: connection refused

Я следил за реализациейс здесь .

Некоторые сведения о моем коде:

server.go

  1. init UDPсервер

  2. начать прослушивание пакетов с заданным IP: PORT (пользовательский ввод)

  3. a. получите пакет типа new_connection для нового клиента (еще не существует), сохраните имя клиента, IP: отображение PORT в переменной и отправьте connection_success в ответ.

    b. получить пакет типа connection_request от клиента A, запрашивая данные B, отправить mapping_response пакет клиенту A с данными B и отправить клиенту B peer_request пакет с деталями А.

код для server.go:

package main

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

var mapping map[string]*net.UDPAddr

func initServer(addr string) (*net.UDPConn, error) {
    s, err := net.ResolveUDPAddr("udp4", addr)
    if err != nil {
        fmt.Println(err.Error())
        return nil, err
    }
    c, err := net.ListenUDP("udp4", s)
    return c, nil
}

func main() {
    port := ":" + os.Args[1]
    mapping = make(map[string]*net.UDPAddr)
    c, err := initServer(port)
    defer c.Close()
    if err != nil {
        return
    }
    listen(c)
}

func listen(c *net.UDPConn) {
    buffer := make([]byte, 1024)
    for {
        n, addr, err := c.ReadFromUDP(buffer)
        if err != nil {
            fmt.Println(err.Error())
        } else  {
            s := strings.Split(string(buffer[0:n]), " ")
            packetType, packetData := s[0], s[1]
            go handle(c, packetType, packetData, addr)
        }
    }
}

func addMapping(c *net.UDPConn, data string, addr *net.UDPAddr) {
    if _, ok := mapping[data]; !ok {
        mapping[data] = addr
        fmt.Println(mapping)
        data := generateData("connection_success", "hello")
        sendResponse(c, data, addr)
    }
}

func makeConnection(c *net.UDPConn, name string, addr1 *net.UDPAddr) {
    addr2 := getAddress(name)
    var data string
    data = generateData("mapping_response", addr2.String())
    sendResponse(c, data, addr1)
    data = generateData("peer_request", addr1.String())
    sendResponse(c, data, addr2)
}

func handle(c *net.UDPConn, packetType string, packetData string, addr *net.UDPAddr) {
    switch packetType {
    case "new_connection":
        addMapping(c, packetData, addr)
    case "connection_request":
        makeConnection(c, packetData, addr)
    default:
        break
    }
}

func getAddress(name string) *net.UDPAddr {
    return mapping[name]
}

func generateData(packetType string, packetData string) string {
    return fmt.Sprintf("%s %s", packetType, packetData)
}

func sendResponse(c *net.UDPConn, data string, addr *net.UDPAddr) {
    fmt.Println(data, addr)
    _, err := c.WriteToUDP([]byte(data), addr)
    if err != nil {
        fmt.Println(err.Error())
    }
}  

клиент. go

  1. init UDP-клиент для сервера

  2. получить имя клиента в качестве ввода (ввод пользователя)

  3. отправка пакета типа new_connection на сервер каждые 10 с.

  4. a. получить пакет типа connection_success , спросить пользователя, к которому следует подключиться (клиент B), и отправить connection_request пакет на сервер с запросом деталей B.

    б. получите пакет типа mapping_response , попробуйте подключиться к клиенту B, используя отправку create_connection пакета клиенту B каждые 3 с.

    с. получите пакет типа peer_request , попробуйте то же самое, что и 3b со стороны клиента B.

код для client.go:

package main

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

func initClient(addr string) (*net.UDPConn, error) {
    s, err := net.ResolveUDPAddr("udp4", addr)
    c, err := net.DialUDP("udp4", nil, s)
    if err != nil {
        fmt.Println(err.Error())
        return nil, err
    }
    return c, nil
}

func main() {
    serverAddress := os.Args[1]
    c, err := initClient(serverAddress)
    if err != nil {
        return
    }
    defer c.Close()
    name := getInput()
    go addMappingToServer(c, name)
    listen(c)
}

func addMappingToServer(c *net.UDPConn, name string) {
    for {
        data := generateData("new_connection", name)
        sendPacket(c, data)
        time.Sleep(10*time.Second)
    }
}

func listen(c *net.UDPConn) {
    buffer := make([]byte, 1024)
    for {
        n, addr, err := c.ReadFromUDP(buffer)
        if err != nil {
            fmt.Println(err.Error())
        } else  {
            s := strings.Split(string(buffer[0:n]), " ")
            packetType, packetData := s[0], s[1]
            go handle(c, packetType, packetData, addr)
        }
    }
}

func handle(c *net.UDPConn, packetType string, packetData string, addr *net.UDPAddr) {
    fmt.Println(packetType, packetData)
    switch packetType {
    case "connection_success":
        getPeerMapping(c)
    case "peer_request":
        establishConnectionToPeer(packetData)
    case "mapping_response":
        establishConnectionToPeer(packetData)
    default:
        break
    }
}

func generateData(packetType string, packetData string) string {
    return fmt.Sprintf("%s %s", packetType, packetData)
}

func sendPacket(c *net.UDPConn, data string) {
    _, err := c.Write([]byte(data))
    if err != nil {
        fmt.Println(err.Error())
    }
}

func sendPacketToAddr(c *net.UDPConn, data string, addr *net.UDPAddr) {
    _, err := c.WriteToUDP([]byte(data), addr)
    if err != nil {
        fmt.Println(err.Error())
    }
}

func getInput() string {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print(">> ")
    text, _ := reader.ReadString('\n')
    return text[0:len(text)-1]
}

func getPeerMapping(c *net.UDPConn) {
    peer := getInput()
    data := generateData("connection_request", peer)
    sendPacket(c, data)
}

func establishConnectionToPeer(peerAddr string) {
    c, err := initClient(peerAddr)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    defer c.Close()
    buffer := make([]byte, 1024)
    for {
        data := generateData("establish_connection", "hello")
        sendPacket(c, data)
        n, addr, err := c.ReadFromUDP(buffer)
        if err != nil {
            fmt.Println(err.Error())
        } else {
            fmt.Println("packet recieved from peer data : %s, addr : %#v", string(buffer[0:n]), addr)
            break
        }
        time.Sleep(3*time.Second)
    }

}

Проблема, с которой я сталкиваюсь, заключается в функции

n, addr, err := c.ReadFromUDP(buffer)

внутри createConnectionToPeer , и я получаю сообщение об ошибке, о котором я упоминал выше ( соединение отклонено ).

Сценарий

Клиент A и сервер находятся на 1 хосте, а клиент B на другом. Оба хоста находятся за одним и тем же NAT.

Пример вывода:

для сервера:

map[abc:192.168.0.78:45999 xyz:192.168.0.10:44207]

означает IP-адрес клиента abc: PORT - 192.168.0.78: 45999 , а для xyz - 192.168.0.10: 44207

для клиента abc:

read udp4 192.168.0.78:40934->192.168.0.10:44207: recvfrom: connection refused

для клиента xyz:

read udp4 192.168.0.10:49708->192.168.0.78:45999: recvfrom: connection refused

Проблема ясна: оба клиента открыли другой порт (отличный от того, что они открыли для связи с сервером)

Что не так с клиентским кодом выше, и что я могу сделать, чтобы решить его? Было бы замечательно, если бы кто-то мог предоставить (или изменить выше) кусок кода, чтобы он начал работать.

Я предполагаю, что это не тот случай, когда мой маршрутизатор не поддерживает UDP дырокол, потому что я могу использовать скайп используя его (и я прочитал здесь , что в скайпе используется пробивание отверстий).

...