我在我自己的項目中這樣做,發現這個問題並不複雜。
下面是一個非常簡單的UDP回顯服務器節點。JS
var dgram = require('dgram');
var socket =
dgram.createSocket('udp4');
socket
.on('listening', function()
{
var address = socket.address();
console.log('socket listening ' +
address.address + ':' + address.port);
})
.on('error', function(err)
{
console.log('socket error:\n' + err.stack);
socket.close();
})
.on('message', function(message, rinfo)
{
console.log('message: ' + message + ' from ' +
rinfo.address + ':' + rinfo.port);
var msg = new Buffer(rinfo.address + ':' + rinfo.port);
socket
.send(msg, 0, msg.length,
rinfo.port, rinfo.address,
function(err, bytes)
{
//socket.close();
});
})
.bind(15000);
一個Android客戶端只需發送一個味精到這個節點服務器
System.out.println("UDP hole punching=======================");
class IOth extends Thread
{
@Override
public void run()
{
String sendMsg = "UDP hole punching";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
System.out.println(HPremoteHost); // node server IP
System.out.println(HPremotePort); // 15000
try
{
packet =
new DatagramPacket(buf, buf.length,
InetAddress.getByName(HPremoteHost), HPremotePort);
ds.send(packet);
}
catch (Exception e)
{
System.out.println("error================");
System.out.println(e);
}
}
}
IOth io00 = new IOth();
io00.start();
Android客戶端UDP聽者通過UDPholepunching
class IOLoop extends Thread
{
@Override
public void run()
{
try
{
String msg = "Native.UDPserver.open";
SocketAddress sockAddress;
String address;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true)
{
try
{
ds.receive(packet);
sockAddress = packet.getSocketAddress();
address = sockAddress.toString();
msg = new String(buf, 0, packet.getLength());
System.out.println(msg + " received !!! by " + address);
//this case is UDP HolePunching reaction
if (address.equals(HPaddress1))
{
System.out.println(msg + "hole punched");
//So you can obtain own Global ip& port here.
//exchange this information
//`remoteHost` `remotePort` to another client
//with some method (signaling server)
}
}
catch (IOException e)
{
}
}
}
catch (Exception e)
{
}
}
}
IOLoop io00 = new IOLoop();
io00.start();
獲得普通味精和自己的全球IP &端口使用其他客戶端IP的Android客戶端UDP發件人remoteHost
remotePort
class IOth extends Thread
{
@Override
public void run()
{
String sendMsg = "This is a test message";
byte[] buf = sendMsg.getBytes();
DatagramPacket packet;
try
{
packet =
new DatagramPacket(buf, buf.length,
InetAddress.getByName(remoteHost), remotePort);
ds.send(packet);
}
catch (Exception e)
{
}
}
}
IOth io00 = new IOth();
io00.start();
在Android設備中沒有內部NAT類似的東西。一個設備具有一個或多個網絡[接口](http://docs.oracle.com/javase/tutorial/networking/nifs/definition.html),如果您在正確的收聽,您可以從外部獲得連接(假設你有互聯網許可)。如果您無法檢查嘗試訪問的網絡路徑與設備之間的網絡路徑。 – zapl 2012-04-28 22:06:47
NAT與終端設備無關。該設備剛分配了一個IP地址。無論是否可路由取決於接入點/ DHCP服務器。 – 2012-04-28 22:08:45
它必須與終端設備有關。當使用移動網絡接口地址測試直接P2P連接時,它可以正常連接到較舊的Android設備(Epic 4G),但在連接到Galaxy S2時無法正常連接。 NetworkInterface.getNetWorkInterfaces方法返回的Galaxy地址與外部IP不匹配,而Epic 4G的地址不匹配。顯然,手機的網絡設置有所改變。 – bgroenks 2012-04-29 17:54:57