登錄站點

用戶名

密碼

socket

1已有 679022 次閱讀  2018-03-20 23:36

The Early Solution:

The native Windows Winsock APIs introduced a new feature in Vista called Dual Mode sockets (http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx).  This allows you to create one socket and use it for either IPv4 or IPv6 communication. To do this you create an IPv6 socket, set the IPV6_V6ONLY socket option to false (0), and then append the IPv6 prefix “0:0:0:0:0:FFFF:” to your IPv4 addresses such as “0:0:0:0:0:FFFF:127.0.0.1”.  It takes some getting used to reading your IPv4 addresses like that, but it is easier than trying to manage two different sockets.

Since System.Net.Sockets.Socket is a thin wrapper over the native Winsock APIs, the Dual Mode functionality was immediately available at the .NET layer.  Unfortunately it was difficult to configure and use, and a few scenarios didn’t work (UDP ReceiveMessageFrom, etc.).  Take the following example of a Dual Mode client and server written using .NET 3.5:

// Server
TcpListener listener = new TcpListener(IPAddress.IPv6Any, port);
listener.Server.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
listener.Start();

// Client
Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
IPAddress address = IPAddress.Parse(“::FFFF:” + IPAddress.Loopback.ToString());
socket.Connect(address, port);

This approach gets increasingly difficult for APIs such as Socket.Connect(IPAddress[] list, int port), and is impossible for APIs like Socket.Connect(string hostname, int port).

In .NET 4.0 the SocketOptionName.IPv6Only (27) enum value was added, but otherwise this scenario was unchanged.

The .NET 4.5 Polished Solution:

With .NET 4.5 the entire Socket API has been updated so that Dual Mode is easy to configure, use, and it just works!  The Socket class now has a boolean DualMode property to enable the socket option, a new constructor that does this by default, IPv4 addresses will be internally converted to IPv6 addresses for you, and every API has been validated to make sure it works when Dual Mode is enabled. There is also a new static TcpListener.Create method for creating a simple Dual Mode server.  See what the above code sample looks like now:

// Server
TcpListener listener = TcpListener.Create(port);
listener.Start();

// Client
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPAddress.Loopback, port);

Something similar can be done for TcpClient:

TcpClient client = new TcpClient(AddressFamily.InterNetworkV6);
client.Client.DualMode = true;
client.Connect(IPAddress.Loopback, port);

Note that the APIs listed at the top of this article that internally emulate Dual Mode have not been changed in order to maintain compatibility with existing applications.  Otherwise all Connect, Bind, SendTo, ReceiveFrom, etc. Socket APIs now work with Dual Mode.  There are also some new helper methods on the IPAddress class if you find yourself needing to convert between IPv4 and IPv6 address representations (e.g. 127.0.0.1 to or from ::FFFF:127.0.0.1), see IPAddress.MapToIPv4() and MapToIPv6().

分享 舉報