Java 中的简单 STUN 客户端

问题描述 投票:0回答:3

我发现了几个java STUN实现

我应该使用 Java 和哪些 Stun 库?

另请参阅:STUN、TURN、Java 的 ICE 库

但它是有很多类的罐子。我希望找到单一方法或至少单一小类形式的简单内容。就像下面的Python代码一样。

https://github.com/jtriley/pystun/blob/develop/stun/init.py

合理回答为什么Java中的STUN如此庞大也是可以接受的。

java stun
3个回答
7
投票

合理回答为什么Java中的STUN这么庞大也是可以接受的。

这是一个合理的问题。 STUN 的 99% 只是一个简单的回显/响应协议,供客户端通过其与公共互联网之间的 NAT 自行发现 IP 和端口映射。在用 C++ 构建了一个 STUN 库后,我有了一些见解。

让我们思考一下 STUN 库需要什么:

  • 使用属性字段模式生成 STUN 消息的消息编写器,不仅允许字段以任何顺序出现,还允许添加自定义属性。

  • 消息解析器,可以读回此类消息并转换数据 结构对于代码使用来说是合理的。它需要安全地执行此操作并避免未处理的异常。

  • 用于发送/接收此类消息的套接字网络代码。而且 STUN 服务器在技术上需要监听 2 个 IP 和 2 个端口,因此这使得服务器的网络代码变得更加复杂。

  • 如果我们只关心绑定请求和绑定响应,我们会 完毕。但 STUN RFC 还定义了一组 NAT 分类测试。因此,需要额外的状态机逻辑来完成任何此类库。

  • 如果 STUN 库要一直使用协议提供的安全选项,则需要一定量的加密代码来对消息进行哈希处理和签名

因此,将所有这些组合到一个库中,任何人都可以将其用于 STUN 的所有不同目的,包括映射地址发现、NAT 分类和 ICE 协商,它开始变得很快。

您可以轻松地滚动一些套接字代码来硬编码绑定请求的字节,然后进行一些解析来解析响应。这可能会满足您自己的需求,但一个完善的开源库永远不会以这种方式编写。

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()

 方法中的代码。


4
投票
Java:

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}")
    

2
投票
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()); } }
    
© www.soinside.com 2019 - 2024. All rights reserved.