Socket.Lier et Connecter en utilisant les adresses locales
Pour tester mon serveur/client de l'application, où chaque client est connu par son adresse IP, j'ai créé plusieurs cartes réseau (voir Comment Créer une Carte Réseau Virtuelle .NET?). Les deux 192.168.0.10 et 11 correspondent maintenant aux locaux adaptateurs ethernet (10 étant le "réel", 11 étant une carte de bouclage).
Le client peut Connect
lui-même sur le serveur tant qu'il n'a pas Bind
son socket à une adresse spécifique. Mais si c'est le cas, le serveur n'a rien remarqué et un délai d'attente se produit dans le client (je veux utiliser Bind
que pour des raisons de sécurité, le serveur détecte automatiquement le client se connecte lui-même en regardant l'adresse IP de l'extrémité distante de la nouvelle connexion: le serveur de perte de connexion à la fois si elle ne connaît pas l'adresse IP - auparavant, j'ai été en utilisant plusieurs machines virtuelles, mais il utilise beaucoup plus de RAM et est moins pratique à utiliser).
Voici le code de mon serveur, en écoutant par exemple, sur 192.168.0.10:1234
IPEndPoint myEP = new IPEndPoint(myAddress, myPort);
Socket listeningSocket = new Socket(myAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listeningSocket.Bind(myEP);
listeningSocket.Listen(50);
Socket acceptedSocket = listeningSocket.Accept();
Voici le code de mon client, en liaison par exemple à 192.168.0.11 (un port) et la connexion à 192.168.0.10:1234
Socket socket = new Socket(svrAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(myAddress, 0)); //Bind to local address using automatic port
socket.Connect(new IPEndPoint(svrAddress, svrPort)); //Works fine without Bind, timeout with Bind
J'ai essayé la même chose en utilisant le raccourci adresses IPv6 mais j'obtiens exactement le même résultat.
Si je Bind
le client sur la même adresse (en utilisant un autre port que le serveur), il fonctionne très bien.
Une idée de ce que je fais mal?
MODIFIER Voici mon test de projets (il peut être utile à quelqu'un)
Partie serveur:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
IPAddress[] ips = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
string line = string.Empty;
while (line != "q")
{
//Gets the IP address to listen on.
Console.WriteLine("IP to listen on:");
int count = 0;
foreach (IPAddress ip in ips)
Console.WriteLine("{0}: {1}", ++count, ip.ToString());
string numString = Console.ReadLine();
int pos = Convert.ToInt32(numString) - 1;
IPAddress myAddress = ips[pos]; //Removing or not the scope ID doesn't change anything as "localEndPoint" below will contain it no matter what
//Binds and starts listening.
IPEndPoint myEP = new IPEndPoint(myAddress, 12345);
Socket listeningSocket = new Socket(myAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listeningSocket.Bind(myEP);
listeningSocket.Listen(50);
IPEndPoint localEndPoint = (IPEndPoint)listeningSocket.LocalEndPoint;
Console.WriteLine("Listening on {0}:{1}", localEndPoint.Address, localEndPoint.Port);
Task.Factory.StartNew(() =>
{
try
{
//Accepts new connections and sends some dummy byte array, then closes the socket.
Socket acceptedSocket = listeningSocket.Accept();
IPEndPoint remoteEndPoint = (IPEndPoint)acceptedSocket.RemoteEndPoint;
Console.WriteLine("Accepted connection from {0}:{1}.", remoteEndPoint.Address, remoteEndPoint.Port);
acceptedSocket.Send(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
acceptedSocket.Close(5000);
Console.WriteLine("-= FINISHED =- Type q to quit, anything else to continue");
}
catch (Exception ex)
{ }
});
line = Console.ReadLine();
//Closes the listening socket.
listeningSocket.Close();
}
}
}
}
Partie Client
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
IPAddress[] ips = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
string line = string.Empty;
while (line != "q")
{
//Gets the IP address to connect to (removes the "scope ID" if it's an IPv6).
Console.WriteLine("IP to connect to:");
int count = 0;
foreach (IPAddress ip in ips)
Console.WriteLine("{0}: {1}", ++count, ip.ToString());
string numString = Console.ReadLine();
int pos = Convert.ToInt32(numString) - 1;
IPAddress svrAddress = ips[pos].AddressFamily == AddressFamily.InterNetworkV6
? new IPAddress(ips[pos].GetAddressBytes())
: ips[pos];
Console.WriteLine("Connecting to " + svrAddress);
//Gets the IP address to bind on (can chose "none" - also removes the "scope ID" if it's an IPv6).
Console.WriteLine("IP to bind to:");
Console.WriteLine("0: none");
count = 0;
IPAddress[] filteredIps = ips.Where(i => i.AddressFamily == svrAddress.AddressFamily).ToArray();
foreach (IPAddress ip in filteredIps)
Console.WriteLine("{0}: {1}", ++count, ip.ToString());
numString = Console.ReadLine();
pos = Convert.ToInt32(numString) - 1;
IPEndPoint localEndPoint = (pos == -1)
? null
: new IPEndPoint(
filteredIps[pos].AddressFamily == AddressFamily.InterNetworkV6
? new IPAddress(filteredIps[pos].GetAddressBytes())
: filteredIps[pos]
, 0);
Console.WriteLine("Binding to " + (localEndPoint == null ? "none" : localEndPoint.Address.ToString()));
//Binds to an address if we chose to.
Socket socket = new Socket(svrAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
if (localEndPoint != null)
socket.Bind(localEndPoint);
Task.Factory.StartNew(() =>
{
try
{
//Connects to the server and receives the dummy byte array, then closes the socket.
socket.Connect(new IPEndPoint(svrAddress, 12345));
IPEndPoint remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint;
Console.WriteLine("Connected to {0}:{1}", remoteEndPoint.Address, remoteEndPoint.Port);
byte[] buffer = new byte[10];
Console.WriteLine((socket.Receive(buffer) == buffer.Length) ? "Received message" : "Incorrect message");
socket.Close();
}
catch (Exception ex)
{
//An exception occured: should be a SocketException due to a timeout if we chose to bind to an address.
Console.WriteLine("ERROR: " + ex.ToString());
}
Console.WriteLine("-= FINISHED =- Type q to quit, anything else to continue");
});
line = Console.ReadLine();
}
}
}
}
J'ai d'abord ajouté un petit échantillon (5 lignes pour le serveur, 3 pour le client), puis plus tard, j'ai aussi ajouté la source d'un simple projet de test pour les deux (j'ai pensé qu'il pourrait aider quelqu'un que ça fonctionne, mais peut-être qu'il a également fait peur aux gens qui avaient envie de répondre).
OriginalL'auteur user276648 | 2012-07-02
Vous devez vous connecter pour publier un commentaire.
En fait c'était un problème de configuration avec mes cartes réseau et il a à voir avec "Faibles et Forts modèle d'Hôte".
De ce que j'ai lu ( À l'aide d'une interface réseau spécifique pour une prise en windows ) de liaison sur Windows antérieures à Vista ne fonctionne que pour le trafic entrant, et il ne faisait rien pour le trafic sortant.
À partir de Vista c'est possible, mais par défaut, il ne fonctionne pas: vous devez autoriser le "modèle d'hôte faible" à l'aide de
Voir http://blog.loadbalancer.org/direct-server-return-on-windows-2008-using-loopback-adpter/ pour plus d'info.
MODIFIER
En fait, au lieu de créer plusieurs cartes de bouclage et de modifier leur modèle d'hôte, c'est beaucoup mieux et plus facile de créer une carte de bouclage, de lui donner plusieurs adresses IP sur un autre réseau que celui de votre adresse IP réelle, et ensuite utiliser uniquement des adresses ip pour votre test. De cette façon, il n'y a pas de problème de routage, et vous êtes sûr tout reste locales (comme il n'y a pas de routage entre le réel et la carte de bouclage).
OriginalL'auteur user276648
Utilisez code ci-dessous dans le serveur pour la liaison de connexion sur l'ensemble de l'interface sur le même port.
OriginalL'auteur Prasanna Bhat