ALL, 我正在编写一个需要与服务器建立异步阻塞连接的应用程序。 我有一个带有按钮的GUI表单和一个与BeginConnect / EndConnect对执行连接的类。 该实现遵循this 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);”在回调catch块中,异常未在单击侦听器中捕获。 但是回调中需要try / catch,因为错误连接会引发异常并且不会返回错误。
答案 0 :(得分:2)
因为您使用的是异步BeginConnect,所以回调几乎不会发生在与单击处理程序相同的线程上,因此您的单击处理程序无法捕获异常。
如果需要从异步回调中设置UI元素的状态,通常需要在创建UI的同一线程上执行委托。
从Control派生的任何UI元素都有一些方法可以帮助您执行此操作(InvokeRequired
和BeginInvoke
)。我修改了你的样本以帮助说明这一点。
基本上,如果异步连接回调中出现异常,您可以传入将被调用的Action委托。然后,此错误处理委托可以执行所有工作,以根据异步连接回调期间引发的异常设置UI状态。
因为我们需要传递错误处理委托,所以我们必须创建一个结构(Called ConnectionData)来保存我们需要在异步连接回调中访问的所有状态(套接字和错误处理程序)。 / p>
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;
}
}
}
答案 1 :(得分:1)
有财产Socket.Connected。
答案 2 :(得分:1)
在Windows中
如果没有错误发生,则connect返回零。否则,它返回SOCKET_ERROR,并且可以通过调用检索特定的错误代码 WSAGetLastError。