简体   繁体   中英

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. 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:

    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. So, what's the problem? And how could I solve this? Should I use Select() instead of Poll()?

Just use the asynchronous methods ( ConnectAsync() ), they're meant for this. Don't use exceptions for program logic.

You can synchronously Connect() a TCP socket without blocking:

Manual :

The Connect method will block, unless you specifically set the Blocking property to false prior to calling Connect. 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.

You can use SocketException.ErrorCode to obtain the specific error code. 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.

If the error returned WSAEWOULDBLOCK, the remote host connection has been initiated by a connection-oriented Socket, but has not yet completed successfully. Use the Poll method to determine when the Socket is finished connecting.

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.

This will add complexity if interaction with UI (WinForms / WPF) is needed, due to the Cross-Thread protection.

Also you can use a BackgroundWorker to avoid this issues.

Actually, your code is working on my system. However, you need of course a server which accepts your TCP connection. 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 ):

 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. 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!)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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