使用C#进行SMTP协议客户端开发心得--读取服务器应答篇

以TcpClient连接方式为例,首先取得服务器发回的数据流。

NetworkStream streamAccount=tcpClient.GetStream();

当我们对smtp服务器发送请求,例如连接,传送用户名,密码后,服务器会返回应答数据流。

我们必须对服务器返回数据流进行读取,这一步我经历了3次改动。

** 最开始的程序 ** 是按照《Visaul C#.NET网络核心编程》这本书上的例子来写的:

private string ReadFromNetStream(ref NetworkStream NetStream)
{
byte[] by=new byte[512];
NetStream.Read(by,0,by.Length);
string read=System.Text.Encoding. ASCII .GetString(by);
return read;
}

这种方式其实就是把读到的数据流全部变成字符串形式,但是实际网络传输中,smtp服务器发回的其实不一定全部是有效的命令,命令都是以

  1<crlf>(回车加换行)结束的。因此这样的读取方式存在问题。   
  2  
  3** 修改以后的代码  ** 如下:   
  4  
  5private string ReadFromNetStream(ref NetworkStream NetStream,string strEndFlag)   
  6{   
  7string ResultData = "";   
  8byte[] ubBuff=new byte[1024];   
  9try   
 10{   
 11while(true)   
 12{   
 13int nCount = NetStream.Read(ubBuff,0,ubBuff.Length);   
 14if( nCount &gt; 0 )   
 15{   
 16ResultData += Encoding.ASCII.GetString( ubBuff, 0, nCount);   
 17} 
 18
 19if( ResultData.EndsWith(strEndFlag) )   
 20{   
 21break;   
 22} 
 23
 24if( nCount == 0 )   
 25{   
 26throw new System.Exception("timeout");   
 27}   
 28}   
 29}   
 30catch(System.Exception se)   
 31{   
 32throw se;   
 33MessageBox.Show(se.ToString());   
 34return "";   
 35}   
 36return ResultData;   
 37}   
 38  
 39这样一来,就可以截取出以回车换行结束的命令。但是这样做还是不够正确的,因为smtp服务器在某些情况下会发回一些欢迎信息之类的东西,它们也是以<crlf>(回车加换行)结束的,我们用上边的程序得到的很有可能不是我们实际想要得到的正确命令。   
 40  
 41于是我只有 ** 再次修改程序  ** 如下:   
 42  
 43/**   
 44*   
 45* 读取服务器的返回信息流   
 46*   
 47*/    
 48public string ReadFromNetStream(ref NetworkStream NetStream)   
 49{   
 50  
 51if( NetStream == null )   
 52return ""; 
 53
 54String ResultData = "";   
 55try   
 56{   
 57while(true)   
 58{   
 59string LineData = ReadLineStr(NetStream);   
 60if( null != LineData   
 61&amp;&amp; LineData.Length &gt; 4)   
 62{   
 63if(LineData.Substring(3,1).CompareTo(" ") != 0)   
 64{   
 65ResultData += LineData + "\r\n";   
 66continue;   
 67}   
 68else   
 69{   
 70ResultData += LineData;   
 71break;   
 72}   
 73}   
 74else   
 75{   
 76ResultData += LineData;   
 77break;   
 78}   
 79}   
 80}   
 81catch(Exception e)   
 82{   
 83throw e;   
 84} 
 85
 86return ResultData;   
 87} 
 88
 89/**   
 90*   
 91* 逐行读取服务器的返回信息   
 92*   
 93*/    
 94public byte[] readLine(NetworkStream m_StrmSource)   
 95{   
 96ArrayList lineBuf = new ArrayList();   
 97byte prevByte = 0; 
 98
 99int currByteInt = m_StrmSource.ReadByte();   
100while(currByteInt &gt; -1)   
101{   
102lineBuf.Add((byte)currByteInt); 
103
104if((prevByte == (byte)'\r' &amp;&amp; (byte)currByteInt == (byte)'\n'))   
105{   
106byte[] retVal = new byte[lineBuf.Count-2];   
107lineBuf.CopyTo(0,retVal,0,lineBuf.Count-2);   
108  
109return retVal;   
110}   
111  
112prevByte = (byte)currByteInt; 
113
114currByteInt = m_StrmSource.ReadByte();   
115} 
116
117  
118if(lineBuf.Count &gt; 0)   
119{   
120byte[] retVal = new byte[lineBuf.Count];   
121lineBuf.CopyTo(0,retVal,0,lineBuf.Count); 
122
123return retVal;   
124} 
125
126return null;   
127} 
128
129/**   
130*   
131* 将服务器的返回信息逐行转换成字符串   
132*   
133*/   
134public string ReadLineStr(NetworkStream myStream)   
135{   
136byte[] b = readLine(myStream);   
137if( null == b)   
138{   
139return null;   
140}   
141else   
142{   
143return System.Text.Encoding.ASCII.GetString( b );   
144}   
145}   
146  
147这样一来,我们就能读到那些以3位应答码开始,加一个空格,然后是一些发回的数据流,结尾是回车加换行的正确命令格式。</crlf></crlf>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus