How to check if I'm connected?

2019-05-29 20:55发布

ALL, I am writing an application that will need to have an asynchronous blocking connection to the server. I have a GUI Form with the button and a class that performs a connection with BeginConnect/EndConnect pair. The implementation follows this MSDN example.

However, in the callback method thw exception is thrown.This is what I'm trying to avoid. What I want instead is to check if the connection has been made and if it's not spit the the appropriate error as a text on my GUI form.

I tried to check a return value of BeginConnect(), but it returns prior to calling the static method. I tried to re-throw the exception and catch it when I establish the connection (button click event), but it does not work. Exception is not caught.

How do I check if the connection has been made?

I can probably pass my text control to the connection class and set the text to an error when exception has been caught, but is there any other way?

Thank you.

[EDIT]

class InternetConnector
{
    public void ConnectToHost()
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port);
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        client.Blocking = true;
        client.BeginConnect(ip, new AsyncCallback(ConnectCallback), client);
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket sock = (Socket)ar.AsyncState;
            sock.EndConnect(ar);
            connectDone.Set();
            Connected = true;
        }
        catch (Exception e)
        {
            throw (e);
        }
    }
}

public partial class Form1 : Form
{
    private bool isRunning = false;
    private InternetConnector client = new InternetConnector();

    private void startStop_Click(object sender, EventArgs e)
    {
        try
        {
            if (!isRunning || !InternetConnector.Connected)
            {
                if (!InternetConnector.Connected)
                {
                    client.SetAddress(ipAddress.Text);
                    client.SetPort(Convert.ToInt32(connectionport.Text));
                    client.ConnectToHost();
                    status.Text = "Signals Receiver: Connected";
                    status.ForeColor = Color.Green;
                    startStop.Text = "Stop";
                    isRunning = true;
                }
                else
                {
                    startStop.Text = "Start";
                    client.DisconnectFromHost();
                    isRunning = false;
                }
            }
        }
        catch(Exception ex)
        {
            status.Text = "Socket Error: " + ex.Message;
        }
    }
 }

If I use "throw( e );" in the callback catch block exception is not caught in click listener. But try/catch is required in the callback as faulty connection is throwing exception and not returning error.

3条回答
聊天终结者
2楼-- · 2019-05-29 21:39

Because you are using the asynchronous BeginConnect, the callback almost never happens on the same thread as your click handler, so there is no way for your click handler to catch the exception.

If you need to set the status of a UI element from an asynchronous callback, you generally need to execute a delegate on the same thread that the UI was created on.

Any UI element deriving from Control has some methods to help you do this (InvokeRequired and BeginInvoke). I've modified your sample to help illustrate this.

Basically, you can pass in an Action delegate that will be called with the exception if it occurs in the async Connect callback. This error handling delegate can then do all of the work to set the UI status based on the exception that was thrown during the async connect callback.

Because we need to pass in the error handling delegate, we have to create a structure (Called ConnectionData) to hold the all of the state (the socket and the error handler) we need to access in the async connect callback.

class InternetConnector  
{  
    private struct ConnectionData
    {
        public Action<Exception> ErrorHandler { get; set; }
        public Socket Socket { get; set; }
    }

    public void ConnectToHost(Action<Exception> errorHandler)  
    {  
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port);  
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        var connectionData = new ConnectionData { ErrorHandler = errorHandler, Socket = client };

        client.Blocking = true;  
        client.BeginConnect(ip, new AsyncCallback(ConnectCallback), connectionData);  
    }  

    private static void ConnectCallback(IAsyncResult ar)  
    {  
        ConnectionData connectionData = new ConnectionData();
        try  
        {  
            connectionData = (ConnectionData)ar.AsyncState;  
            connectionData.Socket.EndConnect(ar);  
            connectDone.Set();  
            Connected = true;  
        }  
        catch (Exception e)  
        {  
            if (connectionData.ErrorHandler != null)
                connectionData.ErrorHandler(e);
        }  
    }  
}  

public partial class Form1 : Form       
{       
    private bool isRunning = false;       
    private InternetConnector client = new InternetConnector();       

    private void AsyncErrorHandler(Exception e)
    {
        if (status.InvokeRequired)
        {
            // queue a call to ourself on control's UI thread and immediately return
            status.BeginInvoke(new Action(()=>AsyncErrorHandler(e)));
            return;
        }

        // we are on the right thread to set the status text
        status.Text = "Async Error: " + ex.Message;  
    }

    private void startStop_Click(object sender, EventArgs e)       
    {       
        try       
        {       
            if (!isRunning || !InternetConnector.Connected)       
            {       
                if (!InternetConnector.Connected)       
                {       
                    client.SetAddress(ipAddress.Text);       
                    client.SetPort(Convert.ToInt32(connectionport.Text));       

                    // connect, pass in the method to use for error reporting
                    client.ConnectToHost(AsyncErrorHandler);       

                    status.Text = "Signals Receiver: Connected";       
                    status.ForeColor = Color.Green;       
                    startStop.Text = "Stop";       
                    isRunning = true;       
                }       
                else       
                {       
                    startStop.Text = "Start";       
                    client.DisconnectFromHost();       
                    isRunning = false;       
                }       
            }       
        }       
        catch(Exception ex)       
        {       
            status.Text = "Socket Error: " + ex.Message;       
        }       
    }       
}       
查看更多
对你真心纯属浪费
3楼-- · 2019-05-29 21:46

There is property Socket.Connected.

查看更多
甜甜的少女心
4楼-- · 2019-05-29 21:58

In windows

Return value

If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.

查看更多
登录 后发表回答