Не могу подключиться к собственному приложению TCP-сервера IPv6, работающему в Ubuntu с моно
Моя тестовая инфраструктура состоит из 3 машин: 1 физической машины с Windows 10, работающей под управлением HyperV и 2 виртуальных машины с установленной ОС Ubuntu. Существует полное сетевое соединение между всеми машинами (они проверяют друг друга). Я написал 2 простые программы на C#: TCP-клиент и TCP-сервер (ниже я приложил минимальный код, который воспроизводит проблему). Когда я запускаю клиент на машине с Windows и сервер на одной из машин с Ubuntu, все работает хорошо. Однако, когда я пытаюсь запустить клиент на одном из компьютеров с Ubuntu, а сервер на другом компьютере с Ubuntu, я получаю сообщение об ошибке на стороне клиента:
Информация TCPClientTest.exe: 0: System.Net.Sockets.SocketException (0x80004005): недопустимые аргументы в System.Net.Sockets.TcpClient.Connect (System.Net.IPAddress[] ipAddresses, порт System.Int32) [0x000e9] в <0x000e9] в <<59be416de143456b88b9988284f43350>:0 в System.Net.Sockets.TcpClient.Connect (имя хоста System.String, порт System.Int32) [0x00007] в <59be416de143456b88b9988284f43350>: 0 в хосте System.Net.Cort.Cen, Порт System.Int32) [0x00006] в <59be416de143456b88b9988284f43350>: 0 в TCPClientTest.Program.Main (аргументы System.String[]) [0x00002] в: 0 DateTime = 2016-11-09T21: 25: 42.4641950Z
TCP-клиент:
TcpClient client = new TcpClient("fe80::3", 15000);
NetworkStream stream = client.GetStream();
int number = stream.ReadByte();
stream.Close();
client.Close();
TCP-сервер:
TcpListener server = new TcpListener(IPAddress.IPv6Any, 15000);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream stream = client.GetStream();
stream.WriteByte(199);
stream.Close();
client.Close();
Версия Ubuntu: 16.04 LTS
Mono версия: 4.6 Service Release 0.1 (4.6.1.5)
В чем может быть проблема?
1 ответ
Я нашел проблему. Локальные адреса канала IPv6 связаны с числом, называемым идентификатором области действия, которое указывает сетевой интерфейс, который мы хотели бы использовать для соединения. Похоже, что в системах Linux мы должны явно предоставить эту информацию (даже с помощью ping6, мы должны это сделать), но в Windows нет таких требований, и согласно этой статье https://technet.microsoft.com/pl-pl/ms739166 он использует Neighbor Discovery и пытается найти для нас подходящий интерфейс.
Например: в Windows ping fe80::3
будет работать правильно, но в Linux нам нужно сделать ping6 -I eth0 fe80::3
или же ping6 fe80::3%2
Клиент TCP должен был быть немного изменен, чтобы соответствовать идентификатору области и указать сетевой интерфейс, который он будет использовать для правильной работы:
IPAddress ipAddress = null;
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
IPInterfaceProperties ipIntProperties = networkInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipIntProperties.UnicastAddresses)
{
String addressWithoutScopeId = addr.Address.ToString().Split('%')[0];
if (addressWithoutScopeId.Equals("fe80::2"))
{
ipAddress = addr.Address;
break;
}
}
if (ipAddress != null)
break;
}
var endPoint = new IPEndPoint(ipAddress, 0);
TcpClient client = new TcpClient(endPoint);
client.Connect(IPAddress.Parse("fe80::3"), 15000);
NetworkStream stream = client.GetStream();
int number = stream.ReadByte();
stream.Close();
client.Close();