【发布时间】:2015-05-07 19:09:19
【问题描述】:
我一直在努力解决套接字通信问题,并且我已经组装了一个小型 Windows 窗体应用程序作为测试。这基本上是一个客户端,它将连接到服务器,发送一些字节并断开连接。最终,我也会收到来自服务器的响应,但我现在基本上已经把它去掉了。
据我所知,这段代码可以正常工作,但由于数据的发送是由于在我的 UI 中单击按钮而发生的,因此它需要是异步的。我有一个名为SendDataToServer(byte[] bytesToSend) 的方法,它连接到服务器并传输数据。在我的按钮单击事件处理程序中,我创建了一个将调用此方法的后台工作程序。
如果我的服务器没有启动并运行,我显然会得到一个套接字异常,当然还有其他原因可能会在尝试连接和传输数据的过程中引发异常。使用 backgroundworker 和异步套接字回调(ClientConnectCallback() 和 ClientSendCallback()),确保任何异常都冒泡并在我的 UI 中正确显示的最佳方法是什么?
现在我在异步回调本身的 catch 块内有 MessageBox,但我想知道这是否真的是显示消息的地方,或者是否应该将它们传递回来?
我的代码如下所示:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace ClientTest
{
public partial class MyForm : Form
{
private string ServerIpAddress = "x.x.x.x";
private int ServerPort = 59176;
public Socket ClientSocket;
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
// state object for reading client data asynchronously
public class StateObject
{
// client socket
public Socket socket = null;
// size of receive buffer
public const int BufferSize = 1024;
// receive buffer
public byte[] buffer = new byte[BufferSize];
// all bytes received get added to this
public List<byte> bytes = new List<byte>();
}
public MyForm()
{
InitializeComponent();
}
private void ClientConnectCallback(IAsyncResult asyncResult)
{
try
{
// retrieve the socket from the state object
Socket client = (Socket)asyncResult.AsyncState;
// complete the connection
client.EndConnect(asyncResult);
// signal that the connection has been made
connectDone.Set();
}
catch (SocketException sockEx)
{
// if the server isn't running, we'll get a socket exception here
MessageBox.Show(sockEx.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (ObjectDisposedException)
{
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ClientSendCallback(IAsyncResult asyncResult)
{
try
{
// retrieve the socket from the state object
Socket client = (Socket)asyncResult.AsyncState;
// complete sending the data to the server
int bytesSent = client.EndSend(asyncResult);
// signal that all bytes have been sent
sendDone.Set();
}
catch (ObjectDisposedException objDispEx)
{
Debug.WriteLine(objDispEx.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void SendDataToServer(byte[] bytesToSend)
{
try
{
connectDone.Reset();
sendDone.Reset();
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(ServerIpAddress);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, ServerPort);
ClientSocket.BeginConnect(remoteEndPoint, new AsyncCallback(ClientConnectCallback), ClientSocket);
connectDone.WaitOne();
ClientSocket.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(ClientSendCallback), ClientSocket);
sendDone.WaitOne();
}
catch (ObjectDisposedException objDispEx)
{
Debug.WriteLine(objDispEx.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
}
}
private void buttonSendDataToServer_Click(object sender, EventArgs e)
{
BackgroundWorker bwSendDataToServer = new BackgroundWorker();
bwSendDataToServer.DoWork += bwSendDataToServer_DoWork;
bwSendDataToServer.RunWorkerCompleted += bwSendDataToServer_RunWorkerCompleted;
bwSendDataToServer.RunWorkerAsync();
}
private void bwSendDataToServer_DoWork(object sender, DoWorkEventArgs e)
{
byte[] bytesToSend = new byte[100];
SendDataToServer(bytesToSend);
}
private void bwSendDataToServer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.WriteLine("BackgroundWorker has completed.");
}
}
}
【问题讨论】:
-
您可能会发现以面向任务的模式包装套接字 API 很有用,因此您可以利用 async/await 和相关的异常处理机制。 stackoverflow.com/questions/12630827/…
标签: c# sockets exception-handling backgroundworker