Java UDP 打孔示例——通过防火墙连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9656198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 05:43:33  来源:igfitidea点击:

Java UDP hole punching example - connecting through firewall

javanetworkinghole-punchingstun

提问by Mat B.

Lets say I have two computers.

假设我有两台电脑。

They know each others public and private IPs via ice4j.

他们通过ice4j.

One client listening and the other one sending some string.

一个客户端侦听,另一个客户端发送一些字符串。

I'd like to see this happen via UPD hole punching:

我希望通过 UPD 打孔看到这种情况发生:

Let A be the client requesting the connection

Let B be the client that is responding to the request

Let S be the ice4j STUN server that they contact to initiate the connection
--
A sends a connection request to S

S responds with B's IP and port info, and sends A's IP and port info to B

A sends a UDP packet to B, which B's router firewall drops but it still
punches a hole in A's own firewall where B can connect

B sends a UDP packet to A, that both punches a hole in their own firewall,
and reaches A through the hole that they punched in their own firewall

A and B can now communicate through their established connection without 
the help of S

Could any one post pseudo examples of how to go about doing hole punching through symmetric NAT? Assuming there will be server S that will help to guess the port numbers and establish connection between the client A and B.

任何人都可以发布有关如何通过对称 NAT 进行打孔的伪示例吗?假设有服务器 S 将帮助猜测端口号并在客户端 A 和 B 之间建立连接。

It would be nice if you accounted for double NAT as well.

如果您也考虑双重 NAT,那就太好了。

NOTE:

笔记:

You can use STUN to discover the IP and Port but you have to write your own code that would send the IP:Port to your server via keepalivetechnique.

您可以使用 STUN 来发现 IP 和端口,但您必须编写自己的代码,通过keepalive技术将 IP:Port 发送到您的服务器。

Once one client identifies the other via unique ID on the server it will be provided with the other's client IP:port info to UDP hole punch the data it needs to send and receive.

一旦一个客户端通过服务器上的唯一 ID 识别另一个客户端,它将获得另一个客户端的 IP:port 信息,以便 UDP 打孔它需要发送和接收的数据。

Little update:

小更新:

There is library that is showing up on the horizon for java check it out:
https://github.com/htwg/UCE#readme

有一个库出现在 Java 的地平线上,请查看:https:
//github.com/htwg/UCE#readme

采纳答案by Jason

This example is in C#, not in Java, but the concepts of NAT traversal are language-agnostic.

这个例子是用 C# 写的,不是用 Java 写的,但是 NAT 遍历的概念是语言不可知的。

See Michael Lidgren's network library which has NAT traversal built in.

请参阅内置 NAT 遍历的 Michael Lidgren 的网络库。

Link: http://code.google.com/p/lidgren-network-gen3/Specific C# File Dealing with NAT Traversal: http://code.google.com/p/lidgren-network-gen3/source/browse/trunk/Lidgren.Network/NetNatIntroduction.cs

链接:http: //code.google.com/p/lidgren-network-gen3/处理 NAT 遍历的特定 C# 文件:http: //code.google.com/p/lidgren-network-gen3/source/browse/主干/Lidgren.Network/NetNatIntroduction.cs

The process you've posted is correct. It will work, for only 3 out of 4 general types of NAT devices(I say general because NAT behavior isn't really standardized): Full-Cone NATs, Restricted-Cone NATs, and Port-Restricted-Cone NATs. NAT traversal will not work with Symmetric NATs, which are found mostly in corporate networks for enhanced security. If one party uses a Symmetric NAT and the other party doesn't, it's still possible to traverse the NAT but it requires more guesswork. A Symmetric NAT to Symmetric NAT traversal is extremely difficult - you can read a paper about it here.

您发布的过程是正确的。它仅适用于 4 种通用类型NAT 设备中的3 种(我说通用是因为 NAT 行为并未真正标准化):Full-Cone NAT、Restricted-Cone NAT 和 Port-Restricted-Cone NAT。NAT 穿越不适用于对称 NAT,对称 NAT 主要用于企业网络以增强安全性。如果一方使用对称 NAT 而另一方不使用,则仍然可以穿越 NAT,但这需要更多的猜测。A Symmetric NAT to Symmetric NAT traversal 是极其困难的——你可以在这里阅读一篇关于它的论文

But really, the process you've described works exactly. I've implemented it for my own remote screen sharing program(also in C#, unfortunately). Just make sure you've disabled Windows firewall (if you're using Windows) and third-party firewalls. But yes, I can happily confirm that it will work.

但实际上,您描述的过程完全正确。我已经为我自己的远程屏幕共享程序实现了它(不幸的是,也在 C# 中)。只需确保您已禁用 Windows 防火墙(如果您使用的是 Windows)和第三方防火墙。但是,是的,我可以很高兴地确认它会起作用。

Clarifying the Process of NAT Traversal

澄清NAT穿越的过程

I'm writing this update to clarify the process of NAT traversal for you and future readers. Hopefully, this can be a clear summary of the history and the process.

我写这个更新是为了向您和未来的读者阐明 NAT 穿越的过程。希望这可以是对历史和过程的清晰总结。

Some Reference Sources: http://think-like-a-computer.com/2011/09/16/types-of-nat/, and http://en.wikipedia.org/wiki/Network_address_translation, http://en.wikipedia.org/wiki/IPv4, http://en.wikipedia.org/wiki/IPv4_address_exhaustion.

一些参考来源:http: //think-like-a-computer.com/2011/09/16/types-of-nat/http://en.wikipedia.org/wiki/Network_address_translationhttp:// en.wikipedia.org/wiki/IPv4, http://en.wikipedia.org/wiki/IPv4_address_exhaustion

IPv4 addresses, with the capacity to uniquely name approximately 4.3 billion computers, have run out. Smart people foresaw this problem, and, among other reasons, invented routers to combat IPv4 address exhaustion, by assigning a network of computers connected to itself 1 shared IP address.

能够唯一命名大约 43 亿台计算机的 IPv4 地址已经用完。聪明人预见到了这个问题,除其他原因外,他们发明了路由器来对抗 IPv4 地址耗尽,通过为连接到自身的计算机网络分配 1 个共享 IP 地址。

There are LAN IPs. And then there are WAN IPs. LAN IPs are Local Area Network IPs which uniquely identify computers in a local network, say the desktops, laptops, printers, and smartphones connected to a home router. WAN IPs uniquely identify computers outside of the local area network in a wide area network - commonly taken to mean The Internet. So these routers assign a group of computers 1 WAN IP. Each computer still has its own LAN IP. LAN IPs are what you see when you type ipconfigin your Command Prompt and get IPv4 Address . . . . . . . . 192.168.1.101. WAN IPs are what you see when you connect to cmyip.comand get 128.120.196.204.

有局域网 IP。然后是 WAN IP。LAN IP 是局域网 IP,可唯一标识本地网络中的计算机,例如连接到家庭路由器的台式机、笔记本电脑、打印机和智能手机。WAN IP 在广域网中唯一标识局域网之外的计算机 - 通常指的是 Internet。因此,这些路由器为一组计算机分配了 1 个 WAN IP。每台计算机仍然有自己的 LAN IP。LAN IP 是您ipconfig在命令提示符中键入并获取IPv4 Address . . . . . . . . 192.168.1.101. WAN IP 是您在连接cmyip.com并获得128.120.196.204.

Just as the radio spectrum is bought out, so entire IP ranges are bought out and reserved as well by agencies and organizations, as well as port numbers. The short message is, again, that we don't have any more IPv4 addresses to spare.

正如无线电频谱被买断一样,整个 IP 范围也被机构和组织买断和保留,以及端口号。短消息再次表明,我们没有更多的 IPv4 地址可供使用。

What does this have to do with NAT traversal? Well, since routers were invented, direct connections (end-to-end connectivity) have been somewhat ... impossible, without a few hacks. If you have a network of 2 computers (Computer A and Computer B) both sharing the WAN IP of 128.120.196.204, to which computer does a connection go? I'm talking about an external computer (say google.com) initiatinga connection to 128.120.196.204. The answer is: nobody knows, and neither does the router, which is why the router drops the connection. If Computer A initiatesa connection to, say, google.com, then that's a different story. The router then remembers that Computer A with LAN IP 192.168.1.101intiated a connection to 74.125.227.64(google.com). As Computer A's request packet leaves the router, the router actually re-writesLAN IP 192.168.1.101to the router's WAN IP of 128.120.196.204. So, when google.com receives Computer A's request packet, it sees the sender IP that the router re-wrote, not the LAN IP of Computer A (google.com sees 128.120.196.204as the IP to reply to). When google.com finally replies, the packet reaches the router, the router remembers(it has a state table) that it was expecting a reply from google.com, and it appropriately forwards the packet to Computer A.

这与NAT穿越有什么关系?嗯,自从发明了路由器,直接连接(端到端连接)在某种程度上……不可能,没有一些黑客攻击。如果您有一个由 2 台计算机(计算机 A 和计算机 B)组成的网络,它们都共享 的 WAN IP 128.120.196.204,那么连接会连接到哪台计算机?我说的是一台外部计算机(比如 google.com)启动128.120.196.204. 答案是:没有人知道,路由器也不知道,这就是路由器断开连接的原因。如果计算机 A启动到,例如,的连接google.com,那么情况就不同了。路由器然后记住具有 LAN IP 的计算机 A192.168.1.101启动了一个连接到74.125.227.64(谷歌网站)。当计算机 A 的请求包离开路由器时,路由器实际上LAN IP重写192.168.1.101为路由器的 WAN IP 128.120.196.204。因此,当 google.com 收到计算机 A 的请求数据包时,它看到的是路由器重写的发送方 IP,而不是计算机 A 的 LAN IP(google.com 将其128.120.196.204视为要回复的 IP)。当 google.com 最终回复时,数据包到达路由器,路由器记住(它有一个状态表)它期待来自 google.com 的回复,并适当地将数据包转发到计算机 A。

In other words, your router has no problem when youinitiate the connection - your router will remember to forward the replying packet back to your computer (through that whole process described above). But, when an external server initiates a connection to you, the router can't know which computer the connection was meant for, since Computer A and Computer B both share the WAN IP of 128.120.196.204... unless, there's a clear rule that instructs the router to forward all packets originally going to destination port X, now to go to Computer A, destination port Y. This is known as port-forwarding. Unfortunately, if you're thinking of using port-forwarding for your networking applications, it's not practical, as your users may not understand how to enable it, and may be reluctant to enable it if they think it's a security risk. UPnPsimply refers to the technology that allows you to programatically enable port-forwarding. Unfortunately, if you're thinking of using UPnP to port-forward your networking applications, it's not practical either, as UPnP is not always available, and when it is, it may not turned on by default.

换句话说,当启动连接时,您的路由器没有问题- 您的路由器会记住将回复数据包转发回您的计算机(通过上述整个过程)。但是,当外部服务器向您发起连接,路由器无法知道该连接针对哪台计算机,因为计算机 A 和计算机 B 都共享...的 WAN IP,128.120.196.204除非有明确的规则指示路由器将所有数据包转发到目标端口X,现在转到计算机 A,目标端口Y。这称为端口转发. 不幸的是,如果您正在考虑为您的网络应用程序使用端口转发,这是不切实际的,因为您的用户可能不了解如何启用它,并且如果他们认为这是一个安全风险,他们可能不愿意启用它。UPnP只是指允许您以编程方式启用端口转发的技术。不幸的是,如果您正在考虑使用 UPnP 来端口转发您的网络应用程序,这也不切实际,因为 UPnP 并不总是可用,而且当它可用时,默认情况下它可能不会打开。

So what's the solution then? The solution is to either proxy your entire traffic over your own computer (which you have carefully pre-configured to be globally reachable), or to come up with a way to beat the system. The first solution is (I believe) called TURN, and magically solves all connectivity issues at the price of providing a farm of servers with the available bandwidth. The second solution is called NAT traversal, and it's what we'll be exploring next.

那么有什么解决办法呢?解决方案是通过您自己的计算机代理您的整个流量(您已仔细预配置为全局可访问),或者想出一种方法来击败系统。第一个解决方案是(我相信)称为TURN,以提供具有可用带宽的服务器群为代价神奇地解决了所有连接问题。第二种解决方案称为 NAT 穿越,这就是我们接下来要探索的内容。

Earlier, I described the process of an external server (say google.com) initiating a connection to 128.120.196.204. I said that, without the router having specific rules to understand which computer to forward google's connection request to, the router would simply drop the connection. This was a generalized scenario, and is not accurate because there are different types of NATs. (Note: A router is the actual physical device that you can drop on the floor. NAT (Network Address Translation) is a software process programmed into the router which helps save IPv4 addresses like trees). So, depending on whichNAT the router employs, connection scenarios vary. A router may even combineNAT processes.

早些时候,我描述了外部服务器(比如 google.com)启动到128.120.196.204. 我说过,如果路由器没有特定的规则来了解将谷歌的连接请求转发到哪台计算机,路由器只会断开连接。这是一个普遍的场景,并不准确,因为有不同类型的 NAT。(注意:路由器是您可以放在地板上的实际物理设备。NAT(网络地址转换)是一个编程到路由器中的软件过程,它有助于保存 IPv4 地址,例如树)。因此,根据NAT路由器使用,连接方案有所不同。路由器甚至可以结合NAT 过程。

There are four types of NATs with standardized behavior: Full-Cone NATs, Restricted-Cone NATs, Port-Restricted-Cone NATs, and Symmetric NATs. Aside from these types, there can be other types of NATs with non-standardized behavior, but it's rarer.

有四种具有标准化行为的 NAT:Full-Cone NAT、Restricted-Cone NAT、Port-Restricted-Cone NAT 和对称 NAT。除了这些类型之外,可能还有其他类型的 NAT 具有非标准化行为,但这种情况很少见。

Note: I'm not really too familiar with NATs...it seems like there are many ways of looking at routers, and information on the internet is very spread out on this topic. Classifying NATs by full, restricted, and port-restricted cones has been somewhat deprecated, says Wikipedia? There's something called static and dynamic NATs...just a bunch of various concepts that I can't reconcile together. Nevertheless, the following model worked for my own application. You can find out more about NATs by reading the links below and above and throughout this post. I can't post more about them because I don't really understand much about them.

注意:我对 NAT 不太熟悉……似乎有很多方法可以查看路由器,并且 Internet 上有关此主题的信息非常广泛。维基百科说,按完整的、受限的和端口受限的锥体对 NAT 进行分类已经有些过时了?有一种叫做静态和动态 NAT 的东西......只是一堆我无法协调的各种概念。尽管如此,以下模型适用于我自己的应用程序。您可以通过阅读下面和上面以及整个帖子中的链接来了解有关 NAT 的更多信息。我不能发布更多关于它们的信息,因为我对它们不太了解。

Hoping for some network gurus to correct/add input, so that we can all learn more about this mysterious process.

希望有网络高手纠正/添加输入,让我们都能更多地了解这个神秘的过程。

To answer your questionabout gathering the external IP and Port of each client:

要回答有关收集每个客户端的外部 IP 和端口的问题:

The headers of all UDP packets are structured the samewith onesource IP and onesource port. UDP packet headers do not contain an "internal" source IP and an "external" source IP. UDP packet headers only contain one source IP. If you want to get an "internal" and "external" source IP, you need to actually send the internal source IP as part of your payload.But it doesn't sound like you need an internal source IP and port. It sounds like you only need an external IP and port, as your question stated. Which means that your solution it to simply read the source IP and port off the packet like the fields they are.

所有 UDP 数据包的标头结构相同,具有一个源 IP 和一个源端口。UDP 数据包头不包含“内部”源 IP 和“外部”源 IP。UDP 数据包头仅包含一个源 IP。如果您想获得“内部”和“外部”源 IP,您需要将内部源 IP 作为有效负载的一部分实际发送。但听起来您不需要内部源 IP 和端口。正如您的问题所述,听起来您只需要一个外部 IP 和端口。这意味着您的解决方案是简单地读取源 IP 和端口,就像它们所在的字段一样。

Two scenarios below (they don't really explain anything else):

下面的两个场景(它们并没有真正解释其他任何东西):

LAN Communication

局域网通讯

Computer A has a LAN IP of 192.168.1.101. Computer B has a LAN IP of 192.168.1.102. Computer A sends a packet, from port 3000, to Computer B at port 6000. The source IP on the UDP packet will be 192.168.1.101. And that will be the only IP. "External" has no context here, because the network is purely a local area network. In this example, a wide area network (like the Internet) doesn't exist. About ports though, because I'm unsure about NATs, I'm not sure if the port inscribed on the packet will be 3000. The NAT device mayre-write the packet's port from 3000 to something random like 49826. Either way, you should use whatever port inscribed on the packet to reply - it's what you're supposed to use to reply. So in this example of LAN communication, you need send only one IP - the LAN IP, because that's all that matters. You don't have to worry about the port - the router takes care of that for you. When you receive the packet, you gather the only IP and port simply by reading it off the packet.

计算机 A 的 LAN IP 为 192.168.1.101。计算机 B 的 LAN IP 为 192.168.1.102。计算机 A 从端口 3000 向计算机 B 的端口 6000 发送数据包。UDP 数据包上的源 IP 将为 192.168.1.101。这将是唯一的 IP。“外部”在这里没有上下文,因为网络纯粹是局域网。在此示例中,不存在广域网(如 Internet)。关于端口,因为我不确定 NAT,所以我不确定数据包上的端口是否为 3000。NAT 设备可能将数据包的端口从 3000 重新写入 49826 之类的随机端口。无论哪种方式,您都应该使用数据包上刻有的任何端口进行回复 - 这就是您应该用来回复的端口。因此,在这个 LAN 通信示例中,您只需要发送一个 IP - LAN IP,因为这很重要。您不必担心端口 - 路由器会为您处理。当您收到数据包时,您只需从数据包中读取即可收集到唯一的 IP 和端口。

WAN Communication

广域网通讯

Computer A has a LAN IP, again, of 192.168.1.101. Computer B has a LAN IP, again, of 192.168.1.102. Both Computer A and Computer B will share a WAN IP of 128.120.196.204. Server S is a server, a globally reachable computer on, let's say, an Amazon EC2 server, with a WAN IP of 1.1.1.1. Server S may have a LAN IP, but it's irrelevant. Computer B is irrelevant too.

计算机 A 的 LAN IP 也是 192.168.1.101。计算机 B 的 LAN IP 也是 192.168.1.102。计算机 A 和计算机 B 将共享 128.120.196.204 的 WAN IP。服务器 S 是一台服务器,是一台可在全球范围内访问的计算机,例如 Amazon EC2 服务器,WAN IP 为 1.1.1.1。服务器 S 可能有 LAN IP,但这无关紧要。计算机 B 也无关紧要。

Computer A sends a packet, from port 3000, to Server S. On the way out the router, the packet's source LAN IP from Computer A gets re-written to the WAN IP of the router. The router also re-writes the source port of 300 to 32981. What does Server S see, in terms of the external IP and port? Server S sees 128.120.196.204 as the IP, not 192.168.1.101, and Server S sees 32981 as the port, not 3000. Although these aren't the original IP and ports Computer A used to send the packet, these are the correct IPs and ports to reply to. When you receive the packet, you can only know the WAN IP and rewritten port. If that's what you want (you were asking for just the externalIP and port), then you're set. Otherwise, if you also wanted the internal IP of the sender, you would need to have transmitted that as normal data separatefrom your header.

计算机 A 从端口 3000 向服务器 S 发送数据包。在离开路由器的途中,来自计算机 A 的数据包的源 LAN IP 被重新写入路由器的 WAN IP。路由器也将源端口300改写为32981,Server S看到的外部IP和端口是什么?服务器 S 将 128.120.196.204 视为 IP,而不是 192.168.1.101,服务器 S 将 32981 视为端口,而不是 3000。虽然这些不是计算机 A 用于发送数据包的原始 IP 和端口,但这些是正确的 IP和要回复的端口。当您收到数据包时,您只能知道 WAN IP 和重写的端口。如果这就是您想要的(您只要求外部IP 和端口),那么您就完成了。否则,如果您还想要发件人的内部 IP,您的标题分开

Code:

代码:

As stated above (below To answer your questionabout gathering the external IP), to gather the External IP and Port of each client, you simply read them off the packet. Each datagram sent alwayshas the source IP and source port of the sender; you don't even need a fancy custom protocol because these two fields are always included - every single UDP packet must, by definition, have these two fields.

如上所述(下面回答有关收集外部 IP 的问题),要收集每个客户端的外部 IP 和端口,您只需从数据包中读取它们即可。每个发送的数据报总是有发送方的源IP和源端口;您甚至不需要花哨的自定义协议,因为这两个字段始终包含在内——根据定义,每个 UDP 数据包都必须具有这两个字段。

// Java language
// Buffer for receiving incoming data
byte[] inboundDatagramBuffer = new byte[1024];
DatagramPacket inboundDatagram = new DatagramPacket(inboundDatagramBuffer, inboundDatagramBuffer.length);
// Source IP address
InetAddress sourceAddress = inboundDatagram.getAddress();
// Source port
int sourcePort = inboundDatagram.getPort();
// Actually receive the datagram
socket.receive(inboundDatagram);

Because getAddress()and getPort()can return either the destination or source port, depending on what you set it to be, on the client (sending) machine, call setAddress()and setPort()to the server (receiving) machine, and on the server (receiving) machine, call setAddress()and setPort()back to the client (sending) machine. There must be a way to do this in receive(). Please elaborate if this (getAddress()and getPort()don't return the source IP and port you expect) is your actual roadblock. This is assuming the server to be a "standard" UDP server (it's not a STUN server).

因为getAddress()andgetPort()可以返回目标端口或源端口,这取决于您将其设置为什么,在客户端(发送)机器上,调用setAddress()setPort()到服务器(接收)机器,在服务器(接收)机器上,调用setAddress()setPort()返回到客户端(发送)机器。必须有一种方法可以做到这一点receive()。请详细说明这(getAddress()并且getPort()不要返回您期望的源 IP 和端口)是否是您的实际障碍。这是假设服务器是“标准”UDP 服务器(它不是 STUN 服务器)。

Further Update:

进一步更新:

I read your update about "how to use STUN to take the IP and port from one client and give it to the other"? A STUN server isn't designed to exchange endpoints or perform NAT traversal. A STUN server is designed to tell you your public IP, public port, and type of NAT device (whether it's a Full-Cone NAT, Restricted-Cone NAT, or Port-Restricted Cone NAT). I'd call the middleman server responsible for exchanging endpoints and performing the actual NAT traversal the "introducer". In my personal project, I don't actually need to use STUN to perform NAT traversing. My "introducer" (the middleman server that introduces clients A and B) is a standard server listening for UDP datagrams. As both clients A and B register themselves with the introducer, the introducer reads off their public IP and port and private IP (in case they're on a LAN). The public IP is read off the datagram header, like for all standard UDP datagrams. The private IP is written as part of the datagram payload, and the introducer just reads it as part of the payload. So, about STUN's usefulness, you don't need to rely on STUN to get the public IP and public port of each of your clients - any connected socket can tell you this. I'd say STUN is useful only for determining what type of NAT device your client is under so that you know whether to perform NAT traversal (if the NAT device type is Full-Cone, Restricted, or Port-Restricted), or to perform all-out TURN traffic proxying (if the NAT device type is Symmetric).

我读了您关于“如何使用 STUN 从一个客户端获取 IP 和端口并将其提供给另一个”的更新?STUN 服务器并非旨在交换端点或执行 NAT 穿越。STUN 服务器旨在告诉您您的公共 IP、公共端口和 NAT 设备的类型(无论是 Full-Cone NAT、Restricted-Cone NAT 还是 Port-Restricted Cone NAT)。我将负责交换端点和执行实际 NAT 遍历的中间人服务器称为“介绍人”。在我的个人项目中,我实际上并不需要使用 STUN 来执行 NAT 遍历。我的“介绍人”(介绍客户端 A 和 B 的中间人服务器)是一个标准服务器,监听 UDP 数据报。当客户端 A 和 B 都向介绍人注册时,介绍人会读取他们的公共 IP、端口和私有 IP(以防他们在 LAN 上)。公共 IP 从数据报头中读取,就像所有标准 UDP 数据报一样。私有 IP 作为数据报负载的一部分写入,介绍者只是将其作为负载的一部分读取。因此,关于 STUN 的用处,您不需要依赖 STUN 来获取每个客户端的公共 IP 和公共端口 - 任何连接的套接字都可以告诉您这一点。一世'

Please elaborate on your roadblock: if you want advice on best practices for designing an application messaging protocol, and advice on reading the fields off received messages in an orderly and systematic fashion (based on the comment you posted below), could you share your current method?

请详细说明您的障碍:如果您想要有关设计应用程序消息传递协议的最佳实践的建议,以及有关以有序和系统的方式读取收到的消息字段的建议(基于您在下面发布的评论),您能否分享您的当前方法?

回答by Yahia

Your question is really broad - I can't offer an example but the following links might help (specs, libraries, samples etc.):

您的问题非常广泛 - 我无法提供示例,但以下链接可能会有所帮助(规格、库、示例等):

回答by Jér?me Verstrynge

Your issue is not a Java related. If you know how to open a UDP connection, that is enough. Read the content of the following link. Don't be scared by the title, it also covers UDP. The rest is just Java coding.

您的问题与 Java 无关。如果您知道如何打开 UDP 连接,那就足够了。阅读以下链接的内容。不要被标题吓到,它也涵盖了 UDP。剩下的就是 Java 编码了。

P.S.: In your scenario, there is a missing step. Both A and B must have an open connection to S, because S needs to tell B that A is trying to reach it. If B does not have an open connection to S, there is no way A and B can start communicating together.

PS:在您的场景中,缺少一个步骤。A 和 B 都必须与 S 建立开放连接,因为 S 需要告诉 B A 正在尝试访问它。如果 B 没有与 S 的开放连接,则 A 和 B 无法开始一起通信。

UPDATE

更新

The answer made by Jason contains errors and wild speculation about NAT traversal. One should read the work done by Saikat Guha (mpi-sws.org/~francis/imc05-tcpnat.pdf)to really understand this matter. The cone classification of Wikipedia is completely obsolete and misleading.

Jason 的回答包含错误和关于 NAT 穿越的胡思乱想。应该阅读Saikat Guha所做的工作(mpi-sws.org/~francis/imc05-tcpnat.pdf)才能真正理解这件事。维基百科的锥形分类完全过时且具有误导性。

回答by vladimir e.

STUN basically works as follows: your client behind the firewall connects to a STUN server outside the firewall. The STUN server inspects the packet received from the client and sends the client a response back containing the clients IP and port as they appear to the STUN server.

STUN 的工作原理如下:防火墙后面的客户端连接到防火墙外的 STUN 服务器。STUN 服务器检查从客户端收到的数据包,并向客户端发送回包含客户端 IP 和端口的响应,因为它们出现在 STUN 服务器上。

This is how the client behind the firewall discovers its own external IP and port. As far as I know a STUN server does not normally pass address information from one client to another.

这就是防火墙后面的客户端发现自己的外部 IP 和端口的方式。据我所知,STUN 服务器通常不会将地址信息从一个客户端传递到另一个客户端。

Typically STUN is used to set up media streams through firewalls, when the firewall is already open to signalling traffic - e.g. in VoIP: client contacts a STUN server to discover its own external IP and port for UDP traffic, it then sends its signalling request (SIP INVITE or whatever) to the other client on a well-known open port - including its external UDP address info in the payload (SDP or whatever). So generally one client needs to be reachable over an open port for signalling for peer-to-peer communication.

通常,STUN 用于通过防火墙设置媒体流,当防火墙已经对信令流量开放时 - 例如在 VoIP 中:客户端联系 STUN 服务器以发现其自己的外部 IP 和端口用于 UDP 流量,然后发送其信令请求( SIP INVITE 或其他)到众所周知的开放端口上的其他客户端 - 包括其在有效负载(SDP 或其他)中的外部 UDP 地址信息。因此,通常需要通过开放端口访问一个客户端,以便为点对点通信发出信号。