C# получение IP-адреса клиента, из которого сокет UDP-сервера получил данные
у меня очень странная проблема. Я не могу найти IP-адрес клиента, с которого мой сервер получает данные. Ниже приведен мой класс прослушивателя UDP.
на IPPacketInformation не содержит IP. The clientEndPoint который я ссылаюсь в моем EndReceiveMessageFrom не.
Когда Я
Console.Writeline(((IPEndPoint)clientEndPoint).Address);
Я получаю IP-адрес сервера. У меня есть сервер, размещенный на моей собственной машине, поэтому я получаю собственный IP адрес. Когда я пытаюсь получить доступ к clientEndPoint.remoteEndPoint он выдает ошибку, потому что сокет не подключен (из-за UDP).
таким образом, в основном, клиент с внешнего IP может отправлять данные, но я не могу ответить клиенту, так как я не могу получить его IP. Любая помощь приветствуется!
public class UdpListener
{
private Socket s;
public byte[] ReceiveBuffer = new byte[2048];
public UdpListener()
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
s.Bind(new IPEndPoint(IPAddress.Any, 36200));
}
public void Listen()
{
try
{
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
}
private void Recv(IAsyncResult res)
{
try
{
Socket receiveSocket = (Socket)res.AsyncState;
EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
IPPacketInformation packetInfo;
SocketFlags flags = SocketFlags.None;
int udpMessageLength = receiveSocket.EndReceiveMessageFrom(res, ref flags, ref clientEndPoint, out packetInfo);
byte[] udpMessage = new byte[udpMessageLength];
Array.Copy(ReceiveBuffer, udpMessage, udpMessageLength);
Console.WriteLine(
"{0} bytes received from {1} to {2}",
ReceiveBuffer,
clientEndPoint,
packetInfo.Address
);
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ((IPEndPoint)receiveSocket.LocalEndPoint).Port);
s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
//Process data
RaiseDataReceived(new ReceivedDataArgs(packetInfo.Address, ((IPEndPoint)clientEndPoint).Port, udpMessage));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
}
public delegate void DataReceived(ReceivedDataArgs args);
public event DataReceived DataReceivedEvent;
private void RaiseDataReceived(ReceivedDataArgs args)
{
DataReceivedEvent?.Invoke(args);
}
}
Я попытался отключить брандмауэр, но это не помогает. Я также сделал переадресацию портов на моем маршрутизаторе, поэтому я могу получать данные от внешних клиенты.
редактировать уточнить проблему:
сервер, размещенный на моей машине за NAT с общедоступным IP 214.214.214.214.
клиент-другая машина, за другим NAT с общедоступным IP 910.910.910.910.
клиент отправляет сообщение на сервер, сервер получает его и может читать содержимое. Когда сервер получает IPEndPoint клиента, отображаемый IP-адрес 214.214.214.214 (IP сервера,не Клиент)
редактировать возможно, я должен сказать, что я не мог получать сообщения от клиентов во внешних сетях, пока я не заказал "Динамический IP" от моего ISP. По-прежнему не удается получить общедоступный IP-адрес источника.
редактировать при использовании Wireshark и sniff пакет, отправленный от внешнего клиента на мой сервер, я вижу, что это неправильный src IP. На рисунке ниже src IP - это мой IP-сервер, а не IP-адрес клиента, который отправил данные.
2 ответов
после нескольких дней чтения всего, что я мог бы на маршрутизаторах, сети и написания различных примеров Receive, ReceiveFrom, ReceiveMessageFrom, BeginReceive, BeginReceiveFrom, BeginReceiveMessageFrom и ReceiveAsync - Я решил свою проблему.
я сменил роутер. теперь я могу получить исходный IP-адрес внешнего клиента, используя очень старый маршрутизатор. Маршрутизатор, который я использовал раньше, был новым Docsis 3.1.
Почему он работает со старым маршрутизатором, я не знаю, но по какой-то причине Docsis 3.1 изменил исходный IP на свой собственный IP, прежде чем позволить сообщению UDP на мою машину.
С помощью UdpClient
class вы можете фактически получить удаленную конечную точку при получении сообщения.
для решения этой задачи я использовал следующее решение:
public void StartServer()
{
var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT));
udpServer.BeginReceive(new AsyncCallback(detectionCallback), udpServer);
}
private void detectionCallback(IAsyncResult ar)
{
var client = (ar.AsyncState as UdpClient);
if (client.Client == null) return;
var endPoint = new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT);
var bytes = client.EndReceive(ar, ref endPoint);
Debug.WriteLine($"Detection request from: {endPoint}");
}