以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服务器发回的其实不一定全部是有效的命令,命令都是以<CRLF>(回车加换行)结束的。因此这样的读取方式存在问题。
修改以后的代码如下:
private string ReadFromNetStream(ref NetworkStream NetStream,string strEndFlag)
{
string ResultData = "";
byte[] ubBuff=new byte[1024];
try
{
while(true)
{
int nCount = NetStream.Read(ubBuff,0,ubBuff.Length);
if( nCount > 0 )
{
ResultData += Encoding.ASCII.GetString( ubBuff, 0, nCount);
}
if( ResultData.EndsWith(strEndFlag) )
{
break;
}
if( nCount == 0 )
{
throw new System.Exception("timeout");
}
}
}
catch(System.Exception se)
{
throw se;
MessageBox.Show(se.ToString());
return "";
}
return ResultData;
}
这样一来,就可以截取出以回车换行结束的命令。但是这样做还是不够正确的,因为smtp服务器在某些情况下会发回一些欢迎信息之类的东西,它们也是以<CRLF>(回车加换行)结束的,我们用上边的程序得到的很有可能不是我们实际想要得到的正确命令。
于是我只有再次修改程序如下:
/**
*
* 读取服务器的返回信息流
*
*/
public string ReadFromNetStream(ref NetworkStream NetStream)
{
if( NetStream == null )
return "";
String ResultData = "";
try
{
while(true)
{
string LineData = ReadLineStr(NetStream);
if( null != LineData
&& LineData.Length > 4)
{
if(LineData.Substring(3,1).CompareTo(" ") != 0)
{
ResultData += LineData + "\r\n";
continue;
}
else
{
ResultData += LineData;
break;
}
}
else
{
ResultData += LineData;
break;
}
}
}
catch(Exception e)
{
throw e;
}
return ResultData;
}
/**
*
* 逐行读取服务器的返回信息
*
*/
public byte[] readLine(NetworkStream m_StrmSource)
{
ArrayList lineBuf = new ArrayList();
byte prevByte = 0;
int currByteInt = m_StrmSource.ReadByte();
while(currByteInt > -1)
{
lineBuf.Add((byte)currByteInt);
if((prevByte == (byte)'\r' && (byte)currByteInt == (byte)'\n'))
{
byte[] retVal = new byte[lineBuf.Count-2];
lineBuf.CopyTo(0,retVal,0,lineBuf.Count-2);
return retVal;
}
prevByte = (byte)currByteInt;
currByteInt = m_StrmSource.ReadByte();
}
if(lineBuf.Count > 0)
{
byte[] retVal = new byte[lineBuf.Count];
lineBuf.CopyTo(0,retVal,0,lineBuf.Count);
return retVal;
}
return null;
}
/**
*
* 将服务器的返回信息逐行转换成字符串
*
*/
public string ReadLineStr(NetworkStream myStream)
{
byte[] b = readLine(myStream);
if( null == b)
{
return null;
}
else
{
return System.Text.Encoding.ASCII.GetString( b );
}
}
这样一来,我们就能读到那些以3位应答码开始,加一个空格,然后是一些发回的数据流,结尾是回车加换行的正确命令格式。