UDP 客户端服务器:通过 WAN 使用
UDP Client server: Usage over a WAN
我有一个将数据(服务器)发送到 UDP 客户端的应用程序。只要我知道客户端的目标地址,它就可以在同一台计算机上完美运行,并且可以通过局域网运行。但是,当我通过互联网执行此操作时,它不再有效,因为它没有目标计算机的地址。这是服务器代码:
public ServerSender(String address, Int32 port, int TTL)
{
m_Address = address;
m_Port = port;
m_TTL = TTL;
Init();
}
private Socket m_Socket;
private IPEndPoint m_EndPoint;
private String m_Address;
private Int32 m_Port;
private Int32 m_TTL;
private void Init()
{
IPAddress destAddr = IPAddress.Parse(m_Address);
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_EndPoint = new IPEndPoint(destAddr, m_Port);
}
public void SendBytes(Byte[] bytes)
{
m_Socket.SendTo(bytes, 0, bytes.Length, SocketFlags.None, m_EndPoint);
}
这是客户:
public void Connect(string strAddress, int port)
{
m_Address = IPAddress.Parse(strAddress);
m_Port = port;
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Multicast Socket
m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
m_EndPoint = new IPEndPoint(m_Address, m_Port);
m_Socket.Bind(m_EndPoint);
m_Socket.Connect(m_EndPoint);
IsConnected = true;
this.DoRead();
}
private void DoRead()
{
try
{
m_Socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), m_Socket);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
显然,服务器需要监听远程连接,客户端需要连接到服务器。我认为我可以获得远程地址,然后在 SendBytes 方法中我将发送到远程端点。我尝试过许多不同的异步服务器示例,它们都会导致各种错误。有什么简单的方法可以更改此代码以允许它通过 Internet 连接到远程主机?
谢谢
总结/详细说明评论:
- 您获得了一个具有 public IP 的主机,即直接连接到 inet(您的 'server')
- 您的主机没有 public IP,即通过 gateway/firewall 连接到 inet ...(您的 'client' )
因为我不知道你对网络了解多少:
TCP/UDP 数据包包裹在 IP 数据包中。 IP 处理 IP 地址,TCP 和 UDP 知道端口,但是:TCP 端口 1 和 UDP 端口 1 是不同的东西!
您的网络设置可能类似于 ,带有一些示例 IP:
|--------| 47.46.43.42 |---------|192.168.0.1 |--------|
| Server |======== The INET =========| Gateway |==================| Client |
|--------| 81.82.83.84 |---------| 192.168.0.100|--------|
此处的网关是您的'router'。
您的客户端将配置为将任何不属于本地 LAN 的流量发送到网关(如果您能够从您的客户端浏览网站,则配置正确)。
再次注意:如果目标 IP 属于 'their' 网络,网络设备会将 IP 数据包传送到正确的接收者。如果不知道目标 IP,他们将不会交付给任何人。
如果您的客户端尝试向您的服务器端口 1 发送 UDP 数据包,它将向网关发送一个包含目标 IP 47.46.43.42 和源 IP 192.168.0.100 的 IP 数据包以及目标端口1 和它用来发送数据包的端口(假设端口 2)。网关接收数据包,查看目标 IP 并将 IP 数据包的内容作为新的 IP 数据包发送(目标 47.46.43.42:1,源 81.82.83.84)。它必须使用另一个 UDP 端口进行发送,比如说 15。这里的关键是:它还记得它从 192.168.0.100 端口 2 向 47.46.43.42 端口 1 发送了一个数据包,它自己的端口 15。每当 UDP 数据包到达时在来自 47.46.43.42 的端口 15 上,它可以假设它是应该转发到 192.168.0.100 端口 2 的一些回复。
那么如果服务器收到数据包,它看到的只是(目标IP 47.46.43.42:1,源IP 81.82.83.84:83:15)。如果它想发回一个答案,它会发送一个带有(目的地 81.82.83.84:15,来源 47.46.43.42:1)的 IP 数据包。请注意,服务器只是 'sees' 网关,而不是它背后的客户端!网关收到数据包,回想它刚刚发送了一个 IP 数据包(dest 47.46.43.42:1,source 192.168.0.100:2),假设 IP 数据包是某种应答,并发送一个新的 IP 数据包(dest 192.168 .0.100:2, source 47.46.43.42:1) 以及从服务器接收到客户端的内容。
请特别注意,这只有效因为网关收到来自客户端的数据包 并从中了解到 192.168.0.100 和 81.82.83.84 'speak to each other'。正因为如此,它才知道如何处理来自您的服务器的数据包!
现在让我们反过来试试。有两种可能的情况:
服务器知道您客户端的 IP (192.168.0.100)。回想一下,互联网上的任何设备都不知道这个 IP,因此如果它发出一个 IP 数据包(目标 192.168.0.100,源 81.82.83.84),它将无法到达 网关因为到达网关的唯一数据包是目标 IP 为 47.46.43.42 的数据包。这个选项永远不会起作用。
服务器知道网关的IP,发出一个IP包(目的地47.46.43.42,来源81.82.83.84)。该数据包将到达网关。但是网关应该用它做什么呢?它从来没有记住来自 IP 81.82.83.84 的数据包可能应该转发给您的客户端。
网关学习的唯一方法是客户端首先向您的服务器发送数据包。此选项也不起作用。
因此,它不足以让服务器知道客户端的IP,但网关需要了解服务器和客户端之间的 'conversation'。您的网关的工作方式要求客户端首先 发送一个数据包,精确地使用您要进一步使用的发送端口。如果您的服务器应该向您的客户端 UDP 端口 2 发送数据,则客户端必须首先从 UDP 端口 2 向服务器发送数据包。
您的网关所做的是 NATTING,您最好阅读一下。
不过,我假设您的网络有一些标准设置。这很可能,但从技术上讲,它可能完全不同,也许您的网关充当防火墙,也部分阻止传出流量,也许您的服务器配置为也将您的网关用作网关(很奇怪,但技术上可行)。
因此离线故障排除很困难,如果我不能在这里为您提供 解决方案 (TM),我很抱歉。
PS:您可能想知道为什么您的客户端 可以 将数据包发送到目标 IP 错误的网关,而您的服务器却不能。这与以下事实有关,即在 ethernet layer 上,您的 LAN 是一个单一网络,而互联网不是...
我有一个将数据(服务器)发送到 UDP 客户端的应用程序。只要我知道客户端的目标地址,它就可以在同一台计算机上完美运行,并且可以通过局域网运行。但是,当我通过互联网执行此操作时,它不再有效,因为它没有目标计算机的地址。这是服务器代码:
public ServerSender(String address, Int32 port, int TTL)
{
m_Address = address;
m_Port = port;
m_TTL = TTL;
Init();
}
private Socket m_Socket;
private IPEndPoint m_EndPoint;
private String m_Address;
private Int32 m_Port;
private Int32 m_TTL;
private void Init()
{
IPAddress destAddr = IPAddress.Parse(m_Address);
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_EndPoint = new IPEndPoint(destAddr, m_Port);
}
public void SendBytes(Byte[] bytes)
{
m_Socket.SendTo(bytes, 0, bytes.Length, SocketFlags.None, m_EndPoint);
}
这是客户:
public void Connect(string strAddress, int port)
{
m_Address = IPAddress.Parse(strAddress);
m_Port = port;
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Multicast Socket
m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
m_EndPoint = new IPEndPoint(m_Address, m_Port);
m_Socket.Bind(m_EndPoint);
m_Socket.Connect(m_EndPoint);
IsConnected = true;
this.DoRead();
}
private void DoRead()
{
try
{
m_Socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), m_Socket);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
显然,服务器需要监听远程连接,客户端需要连接到服务器。我认为我可以获得远程地址,然后在 SendBytes 方法中我将发送到远程端点。我尝试过许多不同的异步服务器示例,它们都会导致各种错误。有什么简单的方法可以更改此代码以允许它通过 Internet 连接到远程主机? 谢谢
总结/详细说明评论:
- 您获得了一个具有 public IP 的主机,即直接连接到 inet(您的 'server')
- 您的主机没有 public IP,即通过 gateway/firewall 连接到 inet ...(您的 'client' )
因为我不知道你对网络了解多少: TCP/UDP 数据包包裹在 IP 数据包中。 IP 处理 IP 地址,TCP 和 UDP 知道端口,但是:TCP 端口 1 和 UDP 端口 1 是不同的东西!
您的网络设置可能类似于 ,带有一些示例 IP:
|--------| 47.46.43.42 |---------|192.168.0.1 |--------|
| Server |======== The INET =========| Gateway |==================| Client |
|--------| 81.82.83.84 |---------| 192.168.0.100|--------|
此处的网关是您的'router'。
您的客户端将配置为将任何不属于本地 LAN 的流量发送到网关(如果您能够从您的客户端浏览网站,则配置正确)。
再次注意:如果目标 IP 属于 'their' 网络,网络设备会将 IP 数据包传送到正确的接收者。如果不知道目标 IP,他们将不会交付给任何人。
如果您的客户端尝试向您的服务器端口 1 发送 UDP 数据包,它将向网关发送一个包含目标 IP 47.46.43.42 和源 IP 192.168.0.100 的 IP 数据包以及目标端口1 和它用来发送数据包的端口(假设端口 2)。网关接收数据包,查看目标 IP 并将 IP 数据包的内容作为新的 IP 数据包发送(目标 47.46.43.42:1,源 81.82.83.84)。它必须使用另一个 UDP 端口进行发送,比如说 15。这里的关键是:它还记得它从 192.168.0.100 端口 2 向 47.46.43.42 端口 1 发送了一个数据包,它自己的端口 15。每当 UDP 数据包到达时在来自 47.46.43.42 的端口 15 上,它可以假设它是应该转发到 192.168.0.100 端口 2 的一些回复。
那么如果服务器收到数据包,它看到的只是(目标IP 47.46.43.42:1,源IP 81.82.83.84:83:15)。如果它想发回一个答案,它会发送一个带有(目的地 81.82.83.84:15,来源 47.46.43.42:1)的 IP 数据包。请注意,服务器只是 'sees' 网关,而不是它背后的客户端!网关收到数据包,回想它刚刚发送了一个 IP 数据包(dest 47.46.43.42:1,source 192.168.0.100:2),假设 IP 数据包是某种应答,并发送一个新的 IP 数据包(dest 192.168 .0.100:2, source 47.46.43.42:1) 以及从服务器接收到客户端的内容。
请特别注意,这只有效因为网关收到来自客户端的数据包 并从中了解到 192.168.0.100 和 81.82.83.84 'speak to each other'。正因为如此,它才知道如何处理来自您的服务器的数据包!
现在让我们反过来试试。有两种可能的情况:
服务器知道您客户端的 IP (192.168.0.100)。回想一下,互联网上的任何设备都不知道这个 IP,因此如果它发出一个 IP 数据包(目标 192.168.0.100,源 81.82.83.84),它将无法到达 网关因为到达网关的唯一数据包是目标 IP 为 47.46.43.42 的数据包。这个选项永远不会起作用。
服务器知道网关的IP,发出一个IP包(目的地47.46.43.42,来源81.82.83.84)。该数据包将到达网关。但是网关应该用它做什么呢?它从来没有记住来自 IP 81.82.83.84 的数据包可能应该转发给您的客户端。 网关学习的唯一方法是客户端首先向您的服务器发送数据包。此选项也不起作用。
因此,它不足以让服务器知道客户端的IP,但网关需要了解服务器和客户端之间的 'conversation'。您的网关的工作方式要求客户端首先 发送一个数据包,精确地使用您要进一步使用的发送端口。如果您的服务器应该向您的客户端 UDP 端口 2 发送数据,则客户端必须首先从 UDP 端口 2 向服务器发送数据包。
您的网关所做的是 NATTING,您最好阅读一下。
不过,我假设您的网络有一些标准设置。这很可能,但从技术上讲,它可能完全不同,也许您的网关充当防火墙,也部分阻止传出流量,也许您的服务器配置为也将您的网关用作网关(很奇怪,但技术上可行)。
因此离线故障排除很困难,如果我不能在这里为您提供 解决方案 (TM),我很抱歉。
PS:您可能想知道为什么您的客户端 可以 将数据包发送到目标 IP 错误的网关,而您的服务器却不能。这与以下事实有关,即在 ethernet layer 上,您的 LAN 是一个单一网络,而互联网不是...