gpt4 book ai didi

c# - Socket.Bind 和 Connect 使用本地地址

转载 作者:太空狗 更新时间:2023-10-30 00:08:13 25 4
gpt4 key购买 nike

为了测试我的服务器/客户端应用程序,其中每个客户端都通过其 IP 地址知道,我创建了几个网络适配器(参见 How to Create a Virtual Network Adapter in .NET?)。 192.168.0.10 和 11 现在都对应于本地以太网适配器(10 是“真正的”适配器,11 是环回适配器)。

客户端可以连接自己到服务器,只要它不绑定(bind)它的套接字到特定地址。但是如果是这样,服务器不会注意到任何事情并且客户端会发生超时(出于安全原因,我想使用 Bind 服务器会通过查看 IP 自动检测哪个客户端正在连接自己新连接的远程端点地址:如果服务器不知道 IP 地址,它会立即断开连接 - 以前我使用了几个虚拟机,但它使用了更多的 RAM,并且不太实用).

这是我服务器中的代码,例如在 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();

这是我客户端中的代码,例如绑定(bind)到 192.168.0.11(任何端口)并连接到 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

我使用相应的 IPv6 地址进行了相同的尝试,但得到的结果完全相同。如果我在同一地址上绑定(bind)客户端(使用与服务器不同的端口),它工作正常。

知道我做错了什么吗?

编辑这是我的测试项目(可能对某人有用)

服务器部分:

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();
}
}
}
}

客户端部分

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();
}
}
}
}

最佳答案

实际上这是我的网络适配器的配置问题,它与“弱强主机模型”有关。

根据我的阅读 (Using a specific network interface for a socket in windows),在 Vista 之前的 Windows 上绑定(bind)仅适用于传入流量,而不会对传出流量执行任何操作。

从 Vista 开始,这是可能的,但默认情况下它不会工作:您需要允许使用“弱主机模型”

netsh interface ipv4 set interface "loopback" weakhostreceive=enabled
netsh interface ipv4 set interface "loopback" weakhostsend=enabled

参见 https://web.archive.org/web/20150402200610/http://blog.loadbalancer.org/direct-server-return-on-windows-2008-using-loopback-adpter/了解更多信息。

编辑

实际上,与其创建多个环回适配器并更改它们的主机模型,不如只创建一个环回适配器,在与您的真实 IP 不同的网络上为其提供多个 IP 地址,然后仅使用这些 IP 会更好也更容易供你测试。这样就没有路由问题,而且您可以确定一切都在本地(因为真实适配器和环回适配器之间没有路由)。

关于c# - Socket.Bind 和 Connect 使用本地地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11290323/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com