简体   繁体   English

C# 非阻塞 Socket.Connect()

[英]C# Non-blocking Socket.Connect()

I choose not the use the asynchronous calls since it requires a callback, I'm just curious if there's a way to solve this by utilizing Unix-alike non-blocking socket method: Poll(), as Asyn is created specifically for the Windows environment.我选择不使用异步调用,因为它需要回调,我很好奇是否有办法通过使用类似 Unix 的非阻塞套接字方法来解决这个问题:Poll(),因为 Asyn 是专门为 Windows 环境创建的. I'm researching if this could be done without asynchronous.我正在研究这是否可以在没有异步的情况下完成。

To be noted: NON-BLOCKING != ASYNCHRONOUS :)需要注意的是:非阻塞 != 异步:)

Therefore I have the following approach by turning off the blocking flag of socket & Poll() method:因此,我通过关闭 socket & Poll() 方法的阻塞标志有以下方法:

    try
    {
        IPEndPoint hostEp = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);
        Socket hostSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        hostSock.Blocking = false;
        hostSock.Connect(hostEp);

    }
    catch (Win32Exception se)
    {
        if (ex.ErrorCode == 10035) // WSAEWOULDBLOCK is expected, means connect is in progress
        while (true)
        {
            Console.WriteLine("Connecting in progress");
            bool connected = hostSock.Poll(1000000, SelectMode.SelectWrite);
            if (connected)
            {
                Console.WriteLine("Connected");
                break;
            }

        }
    }

But then SelectMode.SelectWrite doesn't seems reinitiates an connection attempts for me.但是 SelectMode.SelectWrite 似乎并没有为我重新启动连接尝试。 So, what's the problem?所以有什么问题? And how could I solve this?我怎么能解决这个问题? Should I use Select() instead of Poll()?我应该使用Select() 而不是 Poll() 吗?

Just use the asynchronous methods ( ConnectAsync() ), they're meant for this.只需使用异步方法( ConnectAsync() ),它们就是为此而设计的。 Don't use exceptions for program logic.不要对程序逻辑使用异常。

You can synchronously Connect() a TCP socket without blocking:您可以在不阻塞的情况下同步Connect()一个 TCP 套接字:

Manual :手册:

The Connect method will block, unless you specifically set the Blocking property to false prior to calling Connect. Connect 方法将阻塞,除非您在调用 Connect 之前专门将 Blocking 属性设置为 false。 If you are using a connection-oriented protocol like TCP and you do disable blocking, Connect will throw a SocketException because it needs time to make the connection.如果您使用面向连接的协议(如 TCP)并且确实禁用了阻塞,则 Connect 将抛出 SocketException,因为它需要时间来建立连接。

You can use SocketException.ErrorCode to obtain the specific error code.您可以使用 SocketException.ErrorCode 获取具体的错误代码。 After you have obtained this code, refer to the Windows Sockets version 2 API error code documentation in the MSDN library for a detailed description of the error.获取此代码后,请参阅 MSDN 库中的 Windows Sockets 版本 2 API 错误代码文档以获取错误的详细说明。

If the error returned WSAEWOULDBLOCK, the remote host connection has been initiated by a connection-oriented Socket, but has not yet completed successfully.如果错误返回 WSAEWOULDBLOCK,则远程主机连接已由面向连接的 Socket 发起,但尚未成功完成。 Use the Poll method to determine when the Socket is finished connecting.使用 Poll 方法确定 Socket 何时完成连接。

But that is exactly what your code does, so that should just work.但这正是您的代码所做的,因此应该可以正常工作。

You can use threads or tasks in order to launch the Connect without blocking the main thread.您可以使用线程任务来启动 Connect 而不会阻塞主线程。

This will add complexity if interaction with UI (WinForms / WPF) is needed, due to the Cross-Thread protection.由于跨线程保护,如果需要与 UI (WinForms / WPF) 交互,这将增加复杂性。

Also you can use a BackgroundWorker to avoid this issues.您也可以使用BackgroundWorker来避免此问题。

Actually, your code is working on my system.实际上,您的代码正在我的系统上运行。 However, you need of course a server which accepts your TCP connection.但是,您当然需要一个接受 TCP 连接的服务器。 If you do not have that, then you will wait forever.如果你没有那个,那么你将永远等待。 So I guess you are missing a server.所以我猜你缺少一个服务器。

I had the exact question, but for me the answer was rather silly: my code had the stock code for fetching the IpAddress from a string (from microsoft ):我有确切的问题,但对我来说答案很愚蠢:我的代码具有用于从字符串(来自microsoft )获取 IpAddress 的股票代码:

 var ipHostInfo = Dns.GetHostEntry(hostname);
 return ipHostInfo.AddressList[0];

This was all and good, but my tests was testing against "127.0.0.1:9000", which for some reason gnerated the ip address of my actual ethernet connection.这一切都很好,但我的测试是针对“127.0.0.1:9000”进行测试的,由于某种原因,它生成了我实际以太网连接的 IP 地址。 Changing the parsing mechanism to:将解析机制更改为:

if (hostname.Equals("localhost"))
{
    return IPAddress.Parse("127.0.0.1");
}
try
{
    return IPAddress.Parse(hostname);
}
catch (FormatException e)
{
    var ipHostInfo = Dns.GetHostEntry(hostname);
    return ipHostInfo.AddressList[0];
}

did the trick (at least for me!)成功了(至少对我来说!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM