.NET是否获取UdpClient为本地计算机使用的正确IPEndpoint?
我们正在创建一个系统,使用TCP进行主通信,使用UDP进行广播。客户端广播其状态,而服务器侦听其广播,并通过确认客户端使用接收到的消息的IPEndpoint进行连接来作出响应。这里的问题是,当创建服务器时,它从Dns.GetHostAddresses()方法获取IP地址,并将其设置为其IP,然后使用该IP创建TCP套接字。但是,UdpClient执行自己的操作并在我的计算机上发送不同的IPEndpoint(例如适配器2),因此当客户端尝试连接到TCP流时,端点不存在 我不确定在这些情况下如何获得相同的IPEndpoint,因为我也不确定UdpClient类如何返回它。我也不确定是否应该在实际确认数据包中发送端点,但我不应该,因为UdpReceiveResult应该返回服务器计算机的IPEndpoint 下面是一些代码的示例: GetIP4Address:.NET是否获取UdpClient为本地计算机使用的正确IPEndpoint?,.net,sockets,tcp,udp,.net,Sockets,Tcp,Udp,我们正在创建一个系统,使用TCP进行主通信,使用UDP进行广播。客户端广播其状态,而服务器侦听其广播,并通过确认客户端使用接收到的消息的IPEndpoint进行连接来作出响应。这里的问题是,当创建服务器时,它从Dns.GetHostAddresses()方法获取IP地址,并将其设置为其IP,然后使用该IP创建TCP套接字。但是,UdpClient执行自己的操作并在我的计算机上发送不同的IPEndpoint(例如适配器2),因此当客户端尝试连接到TCP流时,端点不存在 我不确定在这些情况下如何获得
public static string GetIP4Address()
{
//Retrieve all ip addresses associated with this computer (like when you invoke "ipconfig" in cmd)
IPAddress[] hostIpAddresses = Dns.GetHostAddresses(Dns.GetHostName());
//We want to look through all of the IP addresses and search for the IPv4 address and return it
foreach (IPAddress ip in hostIpAddresses)
{
if (ip.AddressFamily.Equals(AddressFamily.InterNetwork))
{
return ip.ToString();
}
}
//If it does not exist, we can assume we are offline and to return the localhost address
return Constants.LOCAL_IP;
}
UDP接收数据包任务:
private async Task<Tuple<Packet, IPEndPoint>> ReceivePacket(UdpClient con)
{
byte[] data;
UdpReceiveResult result = await con.ReceiveAsync();
data = result.Buffer;
Packet packet = Packet.Deserialize(data);
return new Tuple<Packet, IPEndPoint>(packet, result.RemoteEndPoint);
}
private async Task ReceivePacket(UdpClient-con)
{
字节[]数据;
UdpReceiveResult结果=等待con.ReceiveAsync();
数据=结果缓冲区;
数据包=数据包。反序列化(数据);
返回新元组(数据包、结果、RemoteEndPoint);
}
使用ReceivePacket初始化客户端/服务器(握手):
专用异步任务握手()
{
//我们寻找最多重试次数的服务器。
int-retryCounter=0;
UdpClient broadcast=新的UdpClient();
//这就是为什么我们需要UPD来完成这项任务,因为我们需要广播
//通过网络请求服务器
IPEndPoint端点=新IPEndPoint(IPAddress.Broadcast,Constants.CONNECTION_PORT);
//我们需要发送一个SYN数据包,让它知道我们正在请求的服务器(如果存在)
//为了握手,我们将数据包序列化
数据包synPacket=新数据包();
synPacket.Flags=PacketFlag.SYN;
字节[]rawSYNPacket=Packet.Serialize(synppacket);
做
{
//发送我们的“广播”
发送(rawSYNPacket,rawSYNPacket.Length,endPoint);
txtMessagesBox.Text+=$“正在等待服务器#{retryCounter}\n”;
//我们在另一个线程上等待响应。
//receive方法是一个阻塞操作,因此我们为它编写了一个扩展方法
//创建一个具有超时的异步方法。
var packetTuple=wait ReceivePacket(广播)。带有超时(TimeSpan.FromSeconds(搜索服务器超时));
//如果没有收到数据包,我们将重试一次,最多重试一次
if(packetTuple==null)
{
++回收计数器;
继续;
}
//如果我们收到一个ACK数据包,那么服务器就存在,我们需要将应用程序配置为客户端
else if(packetTuple.Item1.Flags==PacketFlag.ACK)
{
this.StartClient(packetTuple.Item2);
返回;
}
}
while(重试计数器<最大重试次数);
//如果没有响应,则必须将应用程序配置为服务器
txtMessagesBox.Text+=“好的,我将是服务器\n”;
this.StartServer();
}
我需要知道如何使这些IPEndpoints匹配,以便客户端在收到响应时可以连接到服务器。确保您的TCP服务器正在侦听UDP服务器正在侦听广播的同一本地IP。并确保UDP服务器使用接收广播的相同本地IP发送每个ack。听起来您没有正确执行所有这些操作,但是您没有显示任何服务器端代码。我的问题是,我不知道如何使用UDP服务器正在侦听的同一本地IP,因为我从未实际将UDPClient绑定到IPEndpoint,这就是您的问题。在服务器端,需要将UDP侦听器绑定到TCP服务器绑定到的同一IP。当UDP侦听器接收到广播时,它知道它正在侦听的IP端点,并且知道发送方的IP端点。使用接收广播的相同UDP对象将ACK发送回发送方。当发送方收到ACK时,远程端点将是发送ACK的UDP侦听器的端点,并且扩展为相应的TCP服务器。如果TCP服务器绑定到多个IP,请为每个IP创建单独的UDP侦听器。
private async Task HandShake()
{
// We look for a server up to MAX_RETRY times.
int retryCounter = 0;
UdpClient broadcast = new UdpClient();
// Here is why we need UPD to accomplish this task. Because we need to broadcast
// over the network asking for a server
IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, Constants.CONNECTION_PORT);
// We need to send a SYN packet letting know to the server (If exists) that we are asking
// for a handshake. We serialize the packet
Packet synPacket = new Packet();
synPacket.Flags = PacketFlag.SYN;
byte[] rawSYNPacket = Packet.Serialize(synPacket);
do
{
// Sending our "BROADCAST"
broadcast.Send(rawSYNPacket, rawSYNPacket.Length, endPoint);
txtMessagesBox.Text += $"Waiting a server #{retryCounter}\n";
// We wait for a response on a separate thread.
// The receive method is a blocking operation so we wrote an extension method to
// create an asynchronous method with a timeout.
var packetTuple = await ReceivePacket(broadcast).WithTimeout(TimeSpan.FromSeconds(SEARCH_SERVER_TIMEOUT));
// If no packet is received we try it one more time up to MAX_RETRY times
if (packetTuple == null)
{
++retryCounter;
continue;
}
// If we receive an ACK packet then a server exists and we need to configure the application as client
else if (packetTuple.Item1.Flags == PacketFlag.ACK)
{
this.StartClient(packetTuple.Item2);
return;
}
}
while (retryCounter < MAX_RETRY);
// If no response then the application must be configured as a server
txtMessagesBox.Text += "Ok, I'll be the server\n";
this.StartServer();
}