我发现了几个java STUN实现
有
但它是有很多类的罐子。我希望找到单一方法或至少单一小类形式的简单内容。就像下面的Python代码一样。
https://github.com/jtriley/pystun/blob/develop/stun/init.py
合理回答为什么Java中的STUN如此庞大也是可以接受的。
合理回答为什么Java中的STUN这么庞大也是可以接受的。
这是一个合理的问题。 STUN 的 99% 只是一个简单的回显/响应协议,供客户端通过其与公共互联网之间的 NAT 自行发现 IP 和端口映射。在用 C++ 构建了一个 STUN 库后,我有了一些见解。
让我们思考一下 STUN 库需要什么:
使用属性字段模式生成 STUN 消息的消息编写器,不仅允许字段以任何顺序出现,还允许添加自定义属性。
您可以轻松地滚动一些套接字代码来硬编码绑定请求的字节,然后进行一些解析来解析响应。这可能会满足您自己的需求,但一个完善的开源库永远不会以这种方式编写。
JSTUN 是一个好的开始。我与原作者分享了一些互操作和错误修复代码。他没有积极维护它,但它是 RFC 3489 的一个很好的实现。我什至将它破解了一次以在 Android 上运行。
在JSTUN中生成STUN绑定请求。
MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
sendMH.generateTransactionID();
// add an empty ChangeRequest attribute. Not required by the standard, but JSTUN server requires it
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
byte[] data = sendMH.getBytes();
// not shown - sending the message
然后解析响应:
byte [] receivedData = new byte[500];
// not shown - socket code that receives the messages into receivedData
receiveMH.parseAttributes(receivedData);
MappedAddress ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
然后将上面的内容与一些套接字代码结合起来。将上述内容与套接字代码相结合的最佳示例可以在 DiscoveryTest.java 源文件中找到。您实际上只需要此类的
test1()
方法中的代码。
MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
// sendMH.generateTransactionID();
// add an empty ChangeRequest attribute. Not required by the
// standard,
// but JSTUN server requires it
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
byte[] data = sendMH.getBytes();
s = new DatagramSocket();
s.setReuseAddress(true);
DatagramPacket p = new DatagramPacket(data, data.length, InetAddress.getByName("stun.l.google.com"), 19302);
s.send(p);
DatagramPacket rp;
rp = new DatagramPacket(new byte[32], 32);
s.receive(rp);
MessageHeader receiveMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingResponse);
// System.out.println(receiveMH.getTransactionID().toString() + "Size:"
// + receiveMH.getTransactionID().length);
receiveMH.parseAttributes(rp.getData());
MappedAddress ma = (MappedAddress) receiveMH
.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
System.out.println(ma.getAddress()+" "+ma.getPort());
val sendMH = MessageHeader(MessageHeaderInterface.MessageHeaderType.BindingRequest)
sendMH.generateTransactionID()
println("sent transaction id: ${sendMH.transactionID.toHexString()}")
// add an empty ChangeRequest attribute. Not required by the standard,
// but JSTUN server requires it
val changeRequest = ChangeRequest()
sendMH.addMessageAttribute(changeRequest)
val data:ByteArray = sendMH.bytes
val s = DatagramSocket()
s.reuseAddress = true
val p = DatagramPacket(data,data.size,InetAddress.getByName("stun.l.google.com"),19302)
s.send(p)
val rp = DatagramPacket(ByteArray(32),32)
s.receive(rp)
val receiveMH = MessageHeader(MessageHeaderInterface.MessageHeaderType.BindingResponse)
try
{
receiveMH.parseAttributes(rp.data)
}
catch (e:MessageAttributeParsingException)
{
e.printStackTrace()
}
println("received transaction id: ${receiveMH.transactionID.toHexString()}")
val ma = receiveMH.getMessageAttribute(MessageAttributeInterface.MessageAttributeType.MappedAddress) as MappedAddress
println("${ma.address}:${ma.port}")
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import de.javawi.jstun.attribute.ChangeRequest;
import de.javawi.jstun.attribute.ChangedAddress;
import de.javawi.jstun.attribute.ErrorCode;
import de.javawi.jstun.attribute.MappedAddress;
import de.javawi.jstun.attribute.MessageAttribute;
import de.javawi.jstun.attribute.MessageAttributeException;
import de.javawi.jstun.attribute.MessageAttributeParsingException;
import de.javawi.jstun.header.MessageHeader;
import de.javawi.jstun.header.MessageHeaderParsingException;
import de.javawi.jstun.util.UtilityException;
public class StunTest { public static void main(String[] args) throws UtilityException, IOException {
MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
// sendMH.generateTransactionID();
// add an empty ChangeRequest attribute. Not required by the
// standard,
// but JSTUN server requires it
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
byte[] data = sendMH.getBytes();
DatagramSocket s = new DatagramSocket();
s.setReuseAddress(true);
DatagramPacket p = new DatagramPacket(data, data.length, InetAddress.getByName("stun.l.google.com"), 19302);
s.send(p);
DatagramPacket rp;
rp = new DatagramPacket(new byte[32], 32);
s.receive(rp);
MessageHeader receiveMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingResponse);
// System.out.println(receiveMH.getTransactionID().toString() + "Size:"
// + receiveMH.getTransactionID().length);
try {
receiveMH.parseAttributes(rp.getData());
} catch (MessageAttributeParsingException e) {
e.printStackTrace();
}
MappedAddress ma = (MappedAddress) receiveMH
.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
System.out.println(ma.getAddress()+" "+ma.getPort());
}
}