[英]IPv4 mapped IPv6 addresses
I'm trying to make a IP version-agnostic client/server. 我正在尝试制作与IP版本无关的客户端/服务器。 I've been playing around with this in C++ and came up with something that works using the
IN6ADDR_SETV4MAPPED
macro (as Microsoft so kindly recommends). 我一直在用C ++进行处理,并使用
IN6ADDR_SETV4MAPPED
宏提出了一些IN6ADDR_SETV4MAPPED
(如Microsoft所建议的那样)。 I followed the code sample here to accomplish this; 我在这里遵循了代码示例以完成此操作。 my code that converts the address is no different from the example and everything works.
我的转换地址的代码与示例相同,一切正常。 I can connect to the server from the client by typing in both an IPv4 and IPv6 address (application does the mapping accordingly).
我可以通过输入IPv4和IPv6地址从客户端连接到服务器(应用程序会相应地进行映射)。
Now I'm looking for a solution in C# to upgrade a simple chat server I made and I've been unable to find any resources on how to use mapped addresses. 现在,我正在寻找用C#升级我制作的简单聊天服务器的解决方案,但我找不到任何有关如何使用映射地址的资源。 I haven't found a function that provides the equivalent of
IN6ADDR_SETV4MAPPED
or any other facility in .net. 我还没有找到提供与
IN6ADDR_SETV4MAPPED
等效的IN6ADDR_SETV4MAPPED
或.net中的任何其他功能。 My question is: how can I go about using a IPv4-mapped IPv6 address in C# (client-side)? 我的问题是: 如何在C# (客户端)中使用IPv4映射的IPv6地址 ?
What I've tried: 我尝试过的
"::ffff:"
to dotted IPv4 notation, call Socket.Connect
using this address. "::ffff:"
添加点分IPv4表示法, Socket.Connect
使用该地址调用Socket.Connect
。 Resulting address string looks like ::ffff:127.0.0.1
. ::ffff:127.0.0.1
。 "::ffff:"
. "::ffff:"
。 Convert each octect from dotted format into hex and separate with colons, call Socket.Connect
. Socket.Connect
。 Resulting address string looks like ::ffff:7f:0:0:1
. ::ffff:7f:0:0:1
。 Neither of these approaches have worked so far. 到目前为止,这两种方法均无效。
Code snippet for server: 服务器的代码段:
this.m_endPoint = new IPEndPoint(IPAddress.IPv6Any, 1337);
this.m_server.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
this.m_server.Bind(this.m_endPoint);
this.m_server.Listen(10);
Code snippet for client: 客户的代码段:
public ClientNet(string host, short port)
{
IPAddress ip;
if(IPAddress.TryParse(host, out ip))
{
string[] octs = host.Split(new char[] { '.' });
host = "::ffff:";
for(int i = 0; i < octs.Length; ++i)
{
host += string.Format("{0:x}", int.Parse(octs[i]));
if(i + 1 != octs.Length)
{
host += ":";
}
}
}
else
{
throw new ClientCreateException("[in ClientNet.Constructor] Unable to create client; use IPv4 address");
}
Socket client = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
client.Connect(host, port);
. . . //More initialization
}
Came back to this today thinking I might be able to figure it out. 今天回到这个问题,以为我也许能弄清楚。 And I did!
而我做到了! The answer is quite easy and I feel like a fool for not getting it for a year.
答案很简单,而且我觉得傻了一年。
Two things about the code I posted: 关于我发布的代码的两件事:
Should have used IPAddress.MaptoIPv6
(see MSDN link) instead of that silly, contrived loop I wrote that's more prone to errors. 应该使用
IPAddress.MaptoIPv6
(请参阅MSDN链接),而不是我写的那个愚蠢的人为设计的循环,它更容易出错。
a. 一种。 I realized later while working in .NET 4.0 that the convenience functions I used in my sample are not available until .NET 4.5.
稍后,我在.NET 4.0中工作时意识到,在示例中使用的便利功能直到.NET 4.5才可用。 A quick code sample I threw together is at the bottom of this post, in case anyone else is stuck in an earlier version of .NET.
我放在一起的快速代码示例在本文的底部,以防万一其他人陷入.NET的早期版本中。
Real solution : Needed to call client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
真正的解决方案 :需要调用
client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
prior to calling client.Connect()
. 在调用
client.Connect()
。
Here is a full code example of a sample application I wrote today to test it out. 这是我今天编写以对其进行测试的示例应用程序的完整代码示例。 I was able to make a connection using both ::1 and 127.0.0.1 as addresses.
我能够使用:: 1和127.0.0.1作为地址进行连接。 Note that the server
Socket
is created for IPv6, and that the SocketOptionName.IPv6Only
option is set to 0 on both the client and the server . 请注意,服务器
Socket
是为IPv6创建的,并且客户端和服务器上的SocketOptionName.IPv6Only
选项都设置为0。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace sixsharp
{
class Program
{
static void Main(string[] args)
{
if(args.Length <= 0) //run as server
RunServer();
else
RunClient(args);
Console.WriteLine("Press enter to close.");
Console.ReadLine();
}
static void RunServer()
{
using(Socket serv = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
{
serv.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
serv.Bind(new IPEndPoint(IPAddress.IPv6Any, 1337));
serv.Listen(5);
Console.Write("Listening for client connection...");
using(Socket client = serv.Accept())
{
Console.WriteLine("Client connection accepted from {0}", client.RemoteEndPoint.ToString());
byte[] buf = new byte[128];
client.Receive(buf, 128, SocketFlags.None);
Console.WriteLine("Got \'{0}\' from client", Encoding.ASCII.GetString(buf));
Console.WriteLine("Echoing response");
client.Send(buf);
client.Shutdown(SocketShutdown.Both);
}
}
Console.WriteLine("Done.");
}
static void RunClient(string[] args)
{
using(Socket client = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
{
client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
Console.WriteLine("Setting up address, input is {0}", args[0]);
IPEndPoint ep;
try
{
ep = new IPEndPoint(IPAddress.Parse(args[0]), 1337);
}
catch(FormatException fe)
{
Console.WriteLine("IP address was improperly formatted and not parsed.");
Console.WriteLine("Detail: {0}", fe.Message);
return;
}
if(ep.AddressFamily == AddressFamily.InterNetwork)
{
ep = new IPEndPoint(ep.Address.MapToIPv6(), ep.Port);
if(!ep.Address.IsIPv4MappedToIPv6 || ep.Address.AddressFamily != AddressFamily.InterNetworkV6)
{
Console.WriteLine("Error mapping IPv4 address to IPv6");
return;
}
}
Console.WriteLine("Connecting to server {0} ...", ep.ToString());
try
{
client.Connect(ep);
}
catch(Exception ex)
{
Console.WriteLine("Unable to connect.\n Detail: {0}", ex.Message);
return;
}
client.Send(Encoding.ASCII.GetBytes("This is a test message. Hello!"));
byte[] buf = new byte[128];
client.Receive(buf);
Console.WriteLine("Got back from server: {0}", Encoding.ASCII.GetString(buf));
client.Shutdown(SocketShutdown.Both);
}
Console.WriteLine("Done.");
}
}
}
Client output: 客户输出:
Setting up address, input is 10.2.6.179
设置地址,输入为10.2.6.179
Connecting to server [::ffff:10.2.6.179]:1337 ...正在连接到服务器[::ffff:10.2.6.179]:1337 ...
Got back from server: This is a test message.从服务器返回:这是一条测试消息。 Hello!
你好!
Done.
做完了
Press enter to close.按Enter键关闭。
Server output: 服务器输出:
Listening for client connection...Client connection accepted from [::ffff:10.2.6.179]:56275
正在侦听客户端连接...客户端连接已从[::ffff:10.2.6.179]:56275接受
Got 'This is a test message.得到了“这是一条测试消息。 Hello!
你好!
' from client来自客户
Echoing response回应回应
Done.做完了
Press enter to close.按Enter键关闭。
Sample extension methods providing the missing convenience functions in earlier versions of .NET: 示例扩展方法提供了.NET早期版本中缺少的便捷功能:
static class IPAddressExtensions
{
public static IPAddress MapToIPv6(this IPAddress addr)
{
if(addr.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Must pass an IPv4 address to MapToIPv6");
string ipv4str = addr.ToString();
return IPAddress.Parse("::ffff:" + ipv4str);
}
public static bool IsIPv4MappedToIPv6(this IPAddress addr)
{
bool pass1 = addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6, pass2;
try
{
pass2 = (addr.ToString().StartsWith("0000:0000:0000:0000:0000:ffff:") ||
addr.ToString().StartsWith("0:0:0:0:0:ffff:") ||
addr.ToString().StartsWith("::ffff:")) &&
IPAddress.Parse(addr.ToString().Substring(addr.ToString().LastIndexOf(":") + 1)).AddressFamily == AddressFamily.InterNetwork;
}
catch
{
return false;
}
return pass1 && pass2;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.