C#网络编程中的异常处理
l 摘要
l 网络编程中异常出现场景
l 网络编程中的异常处理
l 小结
摘要
异常的处理是为了保证程序尽量在不可预知的意外情况正常运行,同时异常的处理也是比较繁琐的过程。在网络编程中,不可预知的情况更多,使得开发者在编程时需要编写大量的异常处理代码,本文介绍了C#中一种简单的异常处理方法,减少了开发者的麻烦。本文假设读者对C#的网络编程和委托比较熟悉。
网络编程中异常出现的场景
在编写程序的过程中,为了尽量让程序具有更好的稳定性,减少不可预知因数对程序运行时的影响,我们都需要大量的使用try..catch.. 来处理可能出现的异常。在网络程序的编写过程中,由于网络的不确定因素使得我们需要编写更多的异常处理代码。比如在一个文件传输的程序中,我们可能会出现如下的情形,
我们的程序结构可能会分为如下几层:界面用户操作层、中间的业务逻辑层、以及用来传输文件的Sockets操作层。相应得伪码如下:
// Sockets传输层
class FileSocket{
Public void TransferFile(Socket sock,string Filename,long filesize){
long total=0;
long rdby=0 ;
int len=0 ;
byte[] buffed = new byte[32767] ;
FileStream fin = new FileStream(filename,FileMode.Open , FileAccess.Read) ;
total=fin.Length;
NetworkStream nfs = new NetworkStream(sock) ;
while(rdby<total&&nfs.CanWrite)
{
len =fin.Read(buffed,0,buffed.Length) ;
nfs.Write(buffed, 0,len);
rdby=rdby+len ;
}
fin.Flush();
fin.Close();
return;
}
}
// 逻辑处理层
Class Logic{
FileSocket Fsocket;
Socket sockt;
long filelength;
Public void SendFile(string filename){
Fsocket.TransferFile(socket,filename,filelength);
}
}
// 界面层
Class Client{
Logic logic;
String filename;
Public void Send_Onclick(object o,EventArgs e){
Logic.SendFile(filename);
}
}
显然在上面的代码中我们可以发现,如果有异常发生,我们的程序就会直接崩溃。当然,我们可以通过处理异常的方法来达到让程序不崩溃的目的,比如在我们的最后的Socket传输层来通过Try.Catch来捕获异常。但是,带来的问题就是,作为调用该段代码的程序,比如Logic类中就必须知道异常已经发生。这样的话,我们的FileSocket中的TransferFile方法就必须返回一个值来表示是否发生异常,比如bool类型,或是int类型,同样的作为Logic的上一级调用者Client也必须来判断Logic中是否有异常,同样也需要来进行判断。如果我们的层数更多,或者调用关系更加复杂的话,我们在代码中,对于类似的处理就更加复杂以及麻烦。
如果我们需要在日志文件中记录异常发生的原因和类型以便调试的话,我们可以需要在上述的三个类中都必须进行相应的处理,这样的话,逻辑也显得比较混乱。
网络编程中的异常处理
在前面的场景中,我们已经非常清楚了在网络编程中异常的处理比较麻烦。如果调用关系比较复杂的话,我们对于代码处理和代码的控制就非常麻烦。同时在对异常的处理过程中,用户很可能会需要写入日志文件,写入系统日志,在界面上面显示等等不同操作,那么在不同的层次中捕捉异常了之后,基本很难实现用户这样的要求。
为了简化对异常的处理过程,达到对异常统一处理的目的,我们采用仅对最终调用层的异常进行统一处理,同时提供一个专门处理异常的类对捕获的异常进行操作。比如在上面的例子中,我们仅在最后的Client调用层来处理异常,对其它可能出现的异常不做捕获。
那么,如何让用户可以对捕获的异常进行不同的操作呢?我们可以采用委托来解决这个问题,由用户直接传入需要处理的方法名称,如显示在界面的函数,写入系统日志的函数等等。
因此,我们可以这样定义一个专门处理异常的类来解决这些问题,代码如下:
public delegate void MessageEventHander ();
public class ExceptionHandler{
private const string LOG_SOURCE_NAME = "yourname";
private const string LOG_SOURCE_LOG = "yourlog";
private MessageEventHandler m_showmessage;
public ExceptionHandler() : this(null)
{
}
public ExceptionHandler(MessageEventHandler ShowMessage){
m_showmessage = ShowMessage;
}
public void WriteLog(Exception ex){
if( ! EventLog.Exists( LOG_SOURCE_NAME)){
EventLog.CreateEventSource(LOG_SOURCE_NAME,LOG_SOURCE_LOG);
EventLog.WriteEntry(LOG_SOURCE_NAME,"Write new Log");
}
EventLog.WriteEntry(LOG_SOURCE_NAME,ex.ToString());
}
public static void Publish(Exception ex,MessageEventHandler ShowMessage){
ExceptionHandler handler = new ExceptionHandler(ShowMessage);
handler.WriteLog(ex);
handler.ShowMessage();
}
public static void Publish(Exception ex){
ExceptionHandler handler = new ExceptionHandler();
handler.WriteLog(ex);
}
}
这个上面是一个简单的实现,如果我们需要在处理异常时,完成其它的操作,那么我们可以直接在ExceptionHander类中加入相关的方法即可。
显然,如果客户段需要对捕获的异常进行处理,那么只要实例化一个MessageEventHander的对象,传入相关的方法即可达到目的。
小结
通过上面的例子中,我们实现了一个简单的统一异常处理的类,来达到简化异常处理的目的,用户也可以根据自己的实际需要对该类进行扩展,使对异常的处理更加方便。