1

全部,我正在编写一个需要与服务器建立异步阻塞连接的应用程序。我有一个带有按钮的 GUI 表单和一个与 BeginConnect/EndConnect 对执行连接的类。该实现遵循MSDN 示例。

但是,在回调方法中抛出了异常。这是我试图避免的。我想要的是检查连接是否已经建立,以及它是否没有将适当的错误作为我的 GUI 表单上的文本吐出。

我试图检查 BeginConnect() 的返回值,但它在调用静态方法之前返回。当我建立连接(按钮单击事件)时,我试图重新抛出异常并捕获它,但它不起作用。异常没有被捕获。

如何检查是否已建立连接?

我可能可以将我的文本控件传递给连接类,并在捕获异常时将文本设置为错误,但是还有其他方法吗?

谢谢你。

[编辑]

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

如果我使用“throw(e);” 在回调中捕获块异常未在单击侦听器中捕获。但是回调中需要 try/catch,因为错误的连接会抛出异常而不返回错误。

4

3 回答 3

2

因为您使用的是异步 BeginConnect,所以回调几乎不会发生在与单击处理程序相同的线程上,因此您的单击处理程序无法捕获异常。

如果需要通过异步回调设置 UI 元素的状态,通常需要在创建 UI 的同一线程上执行委托。

任何从 Control 派生的 UI 元素都有一些方法可以帮助您做到这一点(InvokeRequiredBeginInvoke)。我已经修改了您的示例以帮助说明这一点。

基本上,您可以传入一个 Action 委托,如果它发生在异步 Connect 回调中,该委托将被调用。然后,此错误处理委托可以完成所有工作,以根据异步连接回调期间引发的异常设置 UI 状态。

因为我们需要传入错误处理委托,所以我们必须创建一个结构(称为 ConnectionData)来保存我们需要在异步连接回调中访问的所有状态(套接字和错误处理程序)。

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;       
        }       
    }       
}       
于 2012-08-08T20:25:01.117 回答
1

有属性Socket.Connected

于 2012-08-08T19:22:01.570 回答
1

在窗口中

返回值

如果没有发生错误,connect 返回零。否则,它返回 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

于 2012-08-08T19:22:27.283 回答