Created
July 12, 2014 07:50
-
-
Save reterVision/33a72d70194d4a3c272e to your computer and use it in GitHub Desktop.
A dummy UDP hole punching sample in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"time" | |
) | |
type ChatRequest struct { | |
Action string | |
Username string | |
Message string | |
} | |
func main() { | |
if len(os.Args) < 5 { | |
log.Fatal("Usage: ", os.Args[0], " port serverAddr username peername") | |
} | |
port := fmt.Sprintf(":%s", os.Args[1]) | |
serverAddr := os.Args[2] | |
username := os.Args[3] | |
peer := os.Args[4] | |
buf := make([]byte, 2048) | |
// Prepare to register user to server. | |
saddr, err := net.ResolveUDPAddr("udp4", serverAddr) | |
if err != nil { | |
log.Print("Resolve server address failed.") | |
log.Fatal(err) | |
} | |
// Prepare for local listening. | |
addr, err := net.ResolveUDPAddr("udp4", port) | |
if err != nil { | |
log.Print("Resolve local address failed.") | |
log.Fatal(err) | |
} | |
conn, err := net.ListenUDP("udp", addr) | |
if err != nil { | |
log.Print("Listen UDP failed.") | |
log.Fatal(err) | |
} | |
// Send registration information to server. | |
initChatRequest := ChatRequest{ | |
"New", | |
username, | |
"", | |
} | |
jsonRequest, err := json.Marshal(initChatRequest) | |
if err != nil { | |
log.Print("Marshal Register information failed.") | |
log.Fatal(err) | |
} | |
_, err = conn.WriteToUDP(jsonRequest, saddr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
log.Print("Waiting for server response...") | |
_, _, err = conn.ReadFromUDP(buf) | |
if err != nil { | |
log.Print("Register to server failed.") | |
log.Fatal(err) | |
} | |
// Send connect request to server | |
connectChatRequest := ChatRequest{ | |
"Get", | |
username, | |
peer, | |
} | |
jsonRequest, err = json.Marshal(connectChatRequest) | |
if err != nil { | |
log.Print("Marshal connection information failed.") | |
log.Fatal(err) | |
} | |
var serverResponse ChatRequest | |
for i := 0; i < 3; i++ { | |
conn.WriteToUDP(jsonRequest, saddr) | |
n, _, err := conn.ReadFromUDP(buf) | |
if err != nil { | |
log.Print("Get peer address from server failed.") | |
log.Fatal(err) | |
} | |
err = json.Unmarshal(buf[:n], &serverResponse) | |
if err != nil { | |
log.Print("Unmarshal server response failed.") | |
log.Fatal(err) | |
} | |
if serverResponse.Message != "" { | |
break | |
} | |
time.Sleep(10 * time.Second) | |
} | |
if serverResponse.Message == "" { | |
log.Fatal("Cannot get peer's address") | |
} | |
log.Print("Peer address: ", serverResponse.Message) | |
peerAddr, err := net.ResolveUDPAddr("udp4", serverResponse.Message) | |
if err != nil { | |
log.Print("Resolve peer address failed.") | |
log.Fatal(err) | |
} | |
// Start chatting. | |
go listen(conn) | |
for { | |
fmt.Print("Input message: ") | |
message := make([]byte, 2048) | |
fmt.Scanln(&message) | |
messageRequest := ChatRequest{ | |
"Chat", | |
username, | |
string(message), | |
} | |
jsonRequest, err = json.Marshal(messageRequest) | |
if err != nil { | |
log.Print("Error: ", err) | |
continue | |
} | |
conn.WriteToUDP(jsonRequest, peerAddr) | |
} | |
} | |
func listen(conn *net.UDPConn) { | |
for { | |
buf := make([]byte, 2048) | |
n, _, err := conn.ReadFromUDP(buf) | |
if err != nil { | |
log.Print(err) | |
continue | |
} | |
// log.Print("Message from ", addr.IP) | |
var message ChatRequest | |
err = json.Unmarshal(buf[:n], &message) | |
if err != nil { | |
log.Print(err) | |
continue | |
} | |
fmt.Println(message.Username, ":", message.Message) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"log" | |
"net" | |
) | |
var userIP map[string]string | |
type ChatRequest struct { | |
Action string | |
Username string | |
Message string | |
} | |
func main() { | |
userIP = map[string]string{} | |
service := ":9999" | |
udpAddr, err := net.ResolveUDPAddr("udp4", service) | |
if err != nil { | |
log.Fatal(err) | |
} | |
conn, err := net.ListenUDP("udp", udpAddr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
for { | |
handleClient(conn) | |
} | |
} | |
/* | |
Action: | |
New -- Add a new user | |
Get -- Get a user IP address | |
Username: | |
New -- New user's name | |
Get -- The requested user name | |
*/ | |
func handleClient(conn *net.UDPConn) { | |
var buf [2048]byte | |
n, addr, err := conn.ReadFromUDP(buf[0:]) | |
if err != nil { | |
return | |
} | |
var chatRequest ChatRequest | |
err = json.Unmarshal(buf[:n], &chatRequest) | |
if err != nil { | |
log.Print(err) | |
return | |
} | |
switch chatRequest.Action { | |
case "New": | |
remoteAddr := fmt.Sprintf("%s:%d", addr.IP, addr.Port) | |
fmt.Println(remoteAddr, "connecting") | |
userIP[chatRequest.Username] = remoteAddr | |
// Send message back | |
messageRequest := ChatRequest{ | |
"Chat", | |
chatRequest.Username, | |
remoteAddr, | |
} | |
jsonRequest, err := json.Marshal(&messageRequest) | |
if err != nil { | |
log.Print(err) | |
break | |
} | |
conn.WriteToUDP(jsonRequest, addr) | |
case "Get": | |
// Send message back | |
peerAddr := "" | |
if _, ok := userIP[chatRequest.Message]; ok { | |
peerAddr = userIP[chatRequest.Message] | |
} | |
messageRequest := ChatRequest{ | |
"Chat", | |
chatRequest.Username, | |
peerAddr, | |
} | |
jsonRequest, err := json.Marshal(&messageRequest) | |
if err != nil { | |
log.Print(err) | |
break | |
} | |
_, err = conn.WriteToUDP(jsonRequest, addr) | |
if err != nil { | |
log.Print(err) | |
} | |
} | |
fmt.Println("User table:", userIP) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment