实现超时的异步 tcp 连接



>我得到一个异常:

"An unhandled exception of type 'System.NotSupportedException' occurred in 
 System.dll
 Additional information: This protocol version is not supported."

当我运行以下代码时。我正在尝试实现超时的异步 tcp 连接。

我已经看到并阅读了几个堆栈溢出示例,一些使用TcpClient,一些使用Socket。我认为前者包抄了后者,并且是较新的。我正在尝试使用TcpClient.BeginConnect

文档未将 NotSupport 列为此方法可能引发的异常类型之一。如何追踪问题所在?

public class Client
{
    private string m_host;
    private uint m_port;
    private uint m_timeoutMilliseconds;
    private TcpClient m_client;
    public Client(string host, uint port, uint timeoutMilliseconds)
    {
        m_host = host;
        m_port = port;
        m_timeoutMilliseconds = timeoutMilliseconds;
        m_client = new TcpClient();
    }
    public bool Connect()
    {
        IPHostEntry hostInfo = Dns.GetHostEntry(m_host);
        IPAddress ipAddress = hostInfo.AddressList[0];
        IPEndPoint endpoint = new IPEndPoint(ipAddress, (int)m_port);
        IAsyncResult result = m_client.BeginConnect(ipAddress, (int)m_port, new AsyncCallback(OnConnect), m_client);
        result.AsyncWaitHandle.WaitOne((int)m_timeoutMilliseconds, true);
        // SNIP
        return true;
    }
    public void Disconnect()
    {
        throw new NotImplementedException();
    }
    public void MakeRequest(string symbol)
    {
        throw new NotImplementedException();
    }

    private static void OnConnect(IAsyncResult asyncResult)
    {
        Socket socket = (Socket)asyncResult.AsyncState;
        socket.EndConnect(asyncResult);
        Console.WriteLine("Socket connected to {0}"
                        , socket.RemoteEndPoint.ToString());
    }
}
class Program
{
    static void Main(string[] args)
    {
        Client client = new Integration.Client("127.0.0.1", 24001, 360000);
        client.Connect();
    }
}

默认情况下,TcpClient假定您使用的是 IPv4 地址。有一个构造函数重载,允许您指定要使用的地址系列,但这意味着在完成 dns 查找后构造它:

m_client = new TcpClient(ipAddress.AddressFamily);
IAsyncResult result = m_client.BeginConnect(ipAddress, (int)m_port, new AsyncCallback(OnConnect), m_client);

或者,您可以在hostInfo.AddressList中找到 IPv4 地址并连接到该地址 - 这就是BeginConnect(string host, ...)重载在后台为您所做的(除非您在构造函数中指定了 IPv6(。

我不知道为什么他们不只是从您传递的IPAddress中获取AddressFamily,也许是因为底层Socket是在TcpClient构造函数中创建的。我也惊讶地在TcpClient的参考源页面中看到以下内容:

//
// IPv6: Maintain address family for the client
//
AddressFamily m_Family = AddressFamily.InterNetwork;

我不明白这个评论,但显然有人在选择默认值时确实考虑了IPv6。

如果您只在IP4本地地址之后尝试此操作

using System.Linq;
IPAddress ipAddress = Dns.GetHostEntry(m_host).AddressList.FirstOrDefault(x => x.IsIPv6LinkLocal == false);

我刚刚尝试了您的示例并遇到了相同的错误,上面似乎有效。

最新更新