Я пытаюсь соединить двух пиров за одним и тем же NAT, используя UDP дырокол , но каждый раз, когда 1 клиент отправляет пакет UDP другому клиенту, он получает ошибку:
read udp4 192.168.0.xx:xx->192.168.0.xx:xx: recvfrom: connection refused
Я следил за реализациейс здесь .
Некоторые сведения о моем коде:
server.go
init UDPсервер
начать прослушивание пакетов с заданным IP: PORT (пользовательский ввод)
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
init UDP-клиент для сервера
получить имя клиента в качестве ввода (ввод пользователя)
отправка пакета типа new_connection на сервер каждые 10 с.
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 дырокол, потому что я могу использовать скайп используя его (и я прочитал здесь , что в скайпе используется пробивание отверстий).