三个Telnet链接类----来自网络
声明:下面的三个类都是从网上找到的,具体出处不详,哪个类的好坏性能优劣自己把握,可参考使用。拒绝使用商业用途,如产生版权纠纷和本人无关。
一:Telnet链接网络设备,在网上看到C#Telnet连接网络设备的类,程序为命令行程序,具体代码如下:
文件名:Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Net.Sockets;
using System.Net; namespace ConsoleTelnet
{
public class TelNet
{
#region 一些telnet 的数据定义,先没看懂没关系
/// <summary>
/// 标志符,代表是一个TELNET 指令
/// </summary>
readonly Char IAC = Convert.ToChar();
/// <summary>
/// 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
/// </summary>
readonly Char DO = Convert.ToChar();
/// <summary>
/// 表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。
/// </summary>
readonly Char DONT = Convert.ToChar();
/// <summary>
/// 表示希望开始使用或者确认所使用的是指定的选项。
/// </summary>
readonly Char WILL = Convert.ToChar();
/// <summary>
/// 表示拒绝使用或者继续使用指定的选项。
/// </summary>
readonly Char WONT = Convert.ToChar();
/// <summary>
/// 表示后面所跟的是对需要的选项的子谈判
/// </summary>
readonly Char SB = Convert.ToChar();
/// <summary>
/// 子谈判参数的结束
/// </summary>
readonly Char SE = Convert.ToChar();
const Char IS = '';
const Char SEND = '';
const Char INFO = '';
const Char VAR = '';
const Char VALUE = '';
const Char ESC = '';
const Char USERVAR = '';
/// <summary>
/// 流
/// </summary>
byte[] m_byBuff = new byte[];
/// <summary>
/// 收到的控制信息
/// </summary>
private ArrayList m_ListOptions = new ArrayList();
/// <summary>
/// 存储准备发送的信息
/// </summary>
string m_strResp;
/// <summary>
/// 一个Socket 套接字
/// </summary>
private Socket s;
#endregion
/// <summary>
/// 主函数
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//实例化这个对象
TelNet p = new TelNet();
//启动socket 进行telnet 链接
p.doSocket();
}
/// <summary>
/// 启动socket 进行telnet 操作
/// </summary>
private void doSocket()
{
//获得链接的地址,可以是网址也可以是IP
Console.WriteLine("Server Address:");
//解析输入,如果是一个网址,则解析成ip
IPAddress import = GetIP(Console.ReadLine()); //获得端口号
Console.WriteLine("Server Port:");
int port = int.Parse(Console.ReadLine());
//建立一个socket 对象,使用IPV4,使用流进行连接,使用tcp/ip协议
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获得一个链接地址对象(由IP 地址和端口号构成)
IPEndPoint address = new IPEndPoint(import, port);
/*
* 说明此socket 不是处于阻止模式
*
* msdn 对阻止模式的解释:
* ============================================================
* 如果当前处于阻止模式,并且进行了一个并不立即完成的方法调用,
* 则应用程序将阻止执行,直到请求的操作完成后才解除阻止。
* 如果希望在请求的操作尚未完成的情况下也可以继续执行,
* 请将Blocking 属性更改为false。Blocking 属性对异步方法无效。
* 如果当前正在异步发送和接收数据,并希望阻止执行,
* 请使用ManualResetEvent 类。
* ============================================================
*/
s.Blocking = false;
/*
* 开始一个对远程主机连接的异步请求,
* 因为Telnet 使用的是TCP 链接,是面向连接的,
* 所以此处BeginConnect 会启动一个异步请求,
(本文下载自防锈油文档综合站www.hthrt.com。转载请说明出处)
* 请求获得与给的address 的连接
*
* 此方法的第二个函数是一个类型为AsyncCallback 的委托
*
* 这个AsyncCallback msdn 给出的定义如下
* ===================================================================
* 使用AsyncCallback 委托在一个单独的线程中处理异步操作的结果。A
* syncCallback 委托表示在异步操作完成时调用的回调方法。
* 回调方法采用IAsyncResult 参数,该参数随后可用来获取异步操作的结果。
* ===================================================================
* 这个方法里的委托实际上就是当异步请求有回应了之后,执行委托的方法.
* 委托里的参数,实际上就是BeginConnect 的第三个参数,
* 此处为socket 本身
*(本文下载自防锈油文档综合站www.hthrt.com。转载请说明出处)
* 我比较懒,写了一个匿名委托,实际上跟AsyncCallback 效果一个样.
*
*/
s.BeginConnect(
address,
delegate(IAsyncResult ar)
/*
* 此处为一个匿名委托,
* 实际上等于
* 建立一个AsyncCallback 对象,指定后在此引用一个道理
*
* ok 这里的意义是,
* 当远程主机连接的异步请求有响应的时候,执行以下语句
*/
{
try
{
//获得传入的对象(此处对象是BeginConnect 的第三个参数)
Socket sock1 = (Socket)ar.AsyncState; /*
* 如果Socket 在最近操作时连接到远程资源,则为true;否则为false。
*
* 以下是MSDN 对Connected 属性的备注信息
*
=========================================================================
* Connected 属性获取截止到最后的I/O 操作时Socket 的连接状态。
* 当它返回false 时,表明Socket 要么从未连接,要么已断开连接。
*
* Connected 属性的值反映最近操作时的连接状态。如果您需要确定连接的当前状态,
* 请进行非阻止、零字节的Send 调用。
(本文下载自防锈油文档综合站www.hthrt.com。转载请说明出处)
* 如果该调用成功返回或引发WAEWOULDBLOCK 错误代码(10035),
* 则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。
*
=========================================================================
*/
if (sock1.Connected)
{
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
/*
* 此处没再用匿名委托的原因是,
* 一个匿名委托嵌套一个匿名委托,我自己思路跟不上来了...
*
* ok,这里是当Connected 为true 时,
* 使用BeginReceive 方法
* 开始接收信息到m_byBuff(我们在类中定义的私有属性)
*
* 以下是MSDN 对BeginReceive 的一些说明
*
=========================================================================
* 异步BeginReceive 操作必须通过调用EndReceive 方法来完成。
* 通常,该方法由callback 委托调用。此方法在操作完成前不会进入阻止状态。* 若要
一直阻塞到操作完成时为止,请使用Receive 方法重载中的一个。
* 若要取消挂起的BeginReceive,请调用Close 方法。*
==========================================================================
*
* 当接收完成之后,他们就会调用OnRecievedData 方法
* 我在recieveData 所委托的方法OnRecievedData 中调用了sock.EndReceive(ar);
*/
sock1.BeginReceive(m_byBuff, , m_byBuff.Length, SocketFlags.None, recieveData, sock1);
}
}
catch (Exception ex)
{
Console.WriteLine("初始化接收信息出错:" + ex.Message);
}
},
s);
//此处是为了发送指令而不停的循环
while (true)
{
//发送读出的数据
DispatchMessage(Console.ReadLine());
//因为每发送一行都没有发送回车,故在此处补上
DispatchMessage("\r\n");
}
}
/// <summary>
/// 当接收完成后,执行的方法(供委托使用)
/// </summary>
/// <param name="ar"></param>
private void OnRecievedData(IAsyncResult ar)
{
//从参数中获得给的socket 对象
Socket sock = (Socket)ar.AsyncState;
/*
* EndReceive 方法为结束挂起的异步读取
* (貌似是在之前的beginReceive 收到数据之后,
* socket 只是"挂起",并未结束)
* 之后返回总共接收到的字流量
*
* 以下是MSDN 给出的EndReceive 的注意事项
*
=========================================================================================
* EndReceive 方法完成在BeginReceive 方法中启动的异步读取操作。
*
* 在调用BeginReceive 之前,需创建一个实现AsyncCallback 委托的回调方法。
* 该回调方法在单独的线程中执行并在BeginReceive 返回后由系统调用。
* 回调方法必须接受BeginReceive 方法所返回的IAsyncResult 作为参数。
*
* 在回调方法中,调用IAsyncResult 的AsyncState 方法以获取传递给BeginReceive 方法的状态对象。
* 从该状态对象提取接收Socket。在获取Socket 之后,可以调用EndReceive 方法以成功完成读取操作,
* 并返回已读取的字节数。
*
* EndReceive 方法将一直阻止到有数据可用为止。
* 如果您使用的是无连接协议,则EndReceive 将读取传入网络缓冲区中第一个排队的可用数据报。
* 如果您使用的是面向连接的协议,则EndReceive 方法将读取所有可用的数据,
* 直到达到BeginReceive 方法的size 参数所指定的字节数为止。
* 如果远程主机使用Shutdown 方法关闭了Socket 连接,并且所有可用数据均已收到,
* 则EndReceive 方法将立即完成并返回零字节。
*
* 若要获取接收到的数据,请调用IAsyncResult 的AsyncState 方法,
* 然后提取所产生的状态对象中包含的缓冲区。
*
* 若要取消挂起的BeginReceive,请调用Close 方法。
*
=========================================================================================
*/
int nBytesRec = sock.EndReceive(ar);
//如果有接收到数据的话
if (nBytesRec > )
{
//将接收到的数据转个码,顺便转成string 型
string sRecieved = Encoding.GetEncoding("utf-8").GetString(m_byBuff, , nBytesRec); //声明一个字符串,用来存储解析过的字符串
string m_strLine = "";
//遍历Socket 接收到的字符
/*
* 此循环用来调整linux 和windows 在换行上标记的区别
* 最后将调整好的字符赋予给m_strLine
*/
for (int i = ; i < nBytesRec; i++)
{
Char ch = Convert.ToChar(m_byBuff[i]);
switch (ch)
{
case '\r':
m_strLine += Convert.ToString("\r\n");
break;
case '\n':
break;
default:
m_strLine += Convert.ToString(ch);
break;
}
}
try
{
//获得转义后的字符串的长度
int strLinelen = m_strLine.Length;
//如果长度为零
if (strLinelen == )
{
//则返回"\r\n" 即回车换行
m_strLine = Convert.ToString("\r\n");
}
//建立一个流,把接收的信息(转换后的)存进mToProcess 中
Byte[] mToProcess = new Byte[strLinelen];
for (int i = ; i < strLinelen; i++)
mToProcess[i] = Convert.ToByte(m_strLine[i]);
// Process the incoming data
//对接收的信息进行处理,包括对传输过来的信息的参数的存取和
string mOutText = ProcessOptions(mToProcess);
mOutText = ConvertToGB2312(mOutText); //解析命令后返回显示信息(即除掉了控制信息)
if (mOutText != "")
Console.Write(mOutText);
// Respond to any incoming commands
//接收完数据,处理完字符串数据等一系列事物之后,开始回发数据
RespondToOptions();
}
catch (Exception ex)
{
throw new Exception("接收数据的时候出错了! " + ex.Message);
}
}
else// 如果没有接收到任何数据的话
{
// 输出关闭连接
Console.WriteLine("Disconnected", sock.RemoteEndPoint);
// 关闭socket
sock.Shutdown(SocketShutdown.Both);
sock.Close();
Console.Write("Game Over");
Console.ReadLine();
}
}
/// <summary>
/// 发送数据的函数
/// </summary>
private void RespondToOptions()
{
try
{
//声明一个字符串,来存储接收到的参数
string strOption;
/*
* 此处的控制信息参数,是之前接受到信息之后保存的
* 例如255 253 23 等等
* 具体参数的含义需要去查telnet 协议
*/
for (int i = ; i < m_ListOptions.Count; i++)
{
//获得一个控制信息参数
strOption = (string)m_ListOptions[i];
//根据这个参数,进行处理
ArrangeReply(strOption);
}
DispatchMessage(m_strResp);
m_strResp = "";
m_ListOptions.Clear();
}
catch (Exception ers)
{
Console.WriteLine("错错了,在回发数据的时候" + ers.Message);
}
}
/// <summary>
/// 解析接收的数据,生成最终用户看到的有效文字,同时将附带的参数存储起来
/// </summary>
/// <param name="m_strLineToProcess">收到的处理后的数据</param>
/// <returns></returns>
private string ProcessOptions(byte[] m_strLineToProcess)
{
string m_DISPLAYTEXT = "";
string m_strTemp = "";
string m_strOption = "";
string m_strNormalText = "";
bool bScanDone = false;
int ndx = ;
int ldx = ;
char ch;
try
{
//把数据从byte[] 转化成string
for (int i = ; i < m_strLineToProcess.Length; i++)
{
Char ss = Convert.ToChar(m_strLineToProcess[i]);
m_strTemp = m_strTemp + Convert.ToString(ss);
}
//此处意义为,当没描完数据前,执行扫描
while (bScanDone != true)
{
//获得长度
int lensmk = m_strTemp.Length;
//之后开始分析指令,因为每条指令为255 开头,故可以用此来区分出每条指令
ndx = m_strTemp.IndexOf(Convert.ToString(IAC));
//此处为出错判断,本无其他含义
if (ndx > lensmk)
ndx = m_strTemp.Length;
//此处为,如果搜寻到IAC 标记的telnet 指令,则执行以下步骤
if (ndx != -)
{
#region 如果存在IAC 标志位
// 将标志位IAC 的字符赋值给最终显示文字
m_DISPLAYTEXT += m_strTemp.Substring(, ndx);
// 此处获得命令码
ch = m_strTemp[ndx + ];
//如果命令码是253(DO) 254(DONT) 521(WILL) 252(WONT) 的情况下
if (ch == DO || ch == DONT || ch == WILL || ch == WONT)
{
//将以IAC 开头3个字符组成的整个命令存储起来
m_strOption = m_strTemp.Substring(ndx, );
m_ListOptions.Add(m_strOption);
// 将标志位IAC 的字符赋值给最终显示文字
m_DISPLAYTEXT += m_strTemp.Substring(, ndx);
//将处理过的字符串删去
string txt = m_strTemp.Substring(ndx + );
m_strTemp = txt;
}
//如果IAC 后面又跟了个IAC (255)
else if (ch == IAC)
{
//则显示从输入的字符串头开始,到之前的IAC 结束
m_DISPLAYTEXT = m_strTemp.Substring(, ndx);
//之后将处理过的字符串排除出去
m_strTemp = m_strTemp.Substring(ndx + );
}
//如果IAC 后面跟的是SB(250)
else if (ch == SB)
{
m_DISPLAYTEXT = m_strTemp.Substring(, ndx);
ldx = m_strTemp.IndexOf(Convert.ToString(SE));
m_strOption = m_strTemp.Substring(ndx, ldx);
m_ListOptions.Add(m_strOption);
m_strTemp = m_strTemp.Substring(ldx);
}
#endregion
}
//若字符串里已经没有IAC 标志位了
else
{
//显示信息累加上m_strTemp 存储的字段
m_DISPLAYTEXT = m_DISPLAYTEXT + m_strTemp;
bScanDone = true;
}
}
//输出人看到的信息
m_strNormalText = m_DISPLAYTEXT;
}
catch (Exception eP)
{
throw new Exception("解析传入的字符串错误:" + eP.Message);
}
return m_strNormalText;
}
/// <summary>
/// 获得IP 地址
/// </summary>
/// <param name="import"></param>
/// <returns></returns>
private static IPAddress GetIP(string import)
{
//IPHostEntry IPHost = Dns.GetHostEntry(import);
//IPHostEntry IPHost = Dns.GetHostByName(import);
IPAddress[] IPHost = Dns.GetHostAddresses(import); //return IPHost.AddressList[0];
return IPHost[]; //return IPHost;
}
#region magic Function
//解析传过来的参数,生成回发的数据到m_strResp
private void ArrangeReply(string strOption)
{
try
{
Char Verb;
Char Option;
Char Modifier;
Char ch;
bool bDefined = false;
//排错选项,无啥意义
if (strOption.Length < ) return;
//获得命令码
Verb = strOption[];
//获得选项码
Option = strOption[];
//如果选项码为回显(1) 或者是抑制继续进行(3)
if (Option == || Option == )
{
bDefined = true;
}
// 设置回发消息,首先为标志位255
m_strResp += IAC;
//如果选项码为回显(1) 或者是抑制继续进行(3) ==true
if (bDefined == true)
{
#region 继续判断
//如果命令码为253 (DO)
if (Verb == DO)
{
//我设置我应答的命令码为251(WILL) 即为支持回显或抑制继续进行
ch = WILL;
m_strResp += ch;
m_strResp += Option;
}
//如果命令码为254(DONT)
if (Verb == DONT)
{
//我设置我应答的命令码为252(WONT) 即为我也会"拒绝启动" 回显或抑制继续进行
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
//如果命令码为251(WILL)
if (Verb == WILL)
{
//我设置我应答的命令码为253(DO) 即为我认可你使用回显或抑制继续进行
ch = DO;
m_strResp += ch;
m_strResp += Option;
//break;
}
//如果接受到的命令码为251(WONT)
if (Verb == WONT)
{
//应答我也拒绝选项请求回显或抑制继续进行
ch = DONT;
m_strResp += ch;
m_strResp += Option;
// break;
}
//如果接受到250(sb,标志子选项开始)
if (Verb == SB)
{
/*
* 因为启动了子标志位,命令长度扩展到了4字节,
* 取最后一个标志字节为选项码
* 如果这个选项码字节为1(send)
* 则回发为250(SB 子选项开始) + 获取的第二个字节+ 0(is) + 255(标志位IAC) + 240(SE 子
选项结束)
*/
Modifier = strOption[];
if (Modifier == SEND)
{
ch = SB;
m_strResp += ch;
m_strResp += Option;
m_strResp += IS;
m_strResp += IAC;
m_strResp += SE;
}
}
#endregion
}
else //如果选项码不是1 或者3
{
#region 底下一系列代表,无论你发那种请求,我都不干
if (Verb == DO)
{
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == DONT)
{
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == WILL)
{
ch = DONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == WONT)
{
ch = DONT;
m_strResp += ch;
m_strResp += Option;
}
#endregion
}
}
catch (Exception eeeee)
{
throw new Exception("解析参数时出错:" + eeeee.Message);
}
}
/// <summary>
/// 将信息转化成charp[] 流的形式,使用socket 进行发出
/// 发出结束之后,使用一个匿名委托,进行接收,
/// 之后这个委托里,又有个委托,意思是接受完了之后执行OnRecieveData 方法
///
/// </summary>
/// <param name="strText"></param>
void DispatchMessage(string strText)
{
try
{
//申请一个与字符串相当长度的char 流
Byte[] smk = new Byte[strText.Length];
for (int i = ; i < strText.Length; i++)
{
//解析字符串,将其存储到char 流中去
Byte ss = Convert.ToByte(strText[i]);
smk[i] = ss;
}
//发送char 流,之后发送完毕后执行委托中的方法(此处为匿名委托)
/*MSDN 对BeginSend 的解释
*
============================================================================================
===========
* BeginSend 方法可对在Connect、BeginConnect、Accept 或BeginAccept 方法中建立的远程主机启
动异步发送操作。
* 如果没有首先调用Accept、BeginAccept、Connect 或BeginConnect,则BeginSend 将会引发异常。
* 调用BeginSend 方法将使您能够在单独的执行线程中发送数据。
* 您可以创建一个实现AsyncCallback 委托的回调方法并将它的名称传递给BeginSend 方法。
* 为此,您的state 参数至少必须包含用于通信的已连接或默认Socket。
* 如果回调需要更多信息,则可以创建一个小型类或结构,用于保存Socket 和其他所需的信息。
* 通过state 参数将此类的一个实例传递给BeginSend 方法。
* 回调方法应调用EndSend 方法。
* 当应用程序调用BeginSend 时,系统将使用一个单独的线程来执行指定的回调方法,
* 并阻止EndSend,直到Socket 发送了请求的字节数或引发了异常为止。
* 如果希望在调用BeginSend 方法之后使原始线程阻止,请使用WaitHandle.WaitOne 方法。
* 当需要原始线程继续执行时,请在回调方法中调用T:System.Threading.ManualResetEvent 的Set 方
法。
* 有关编写回调方法的其他信息,请参见Callback 示例。
*
============================================================================================
===========
*/
IAsyncResult ar2 = s.BeginSend(smk, , smk.Length, SocketFlags.None, delegate(IAsyncResult ar)
{
//当执行完"发送数据" 这个动作后
// 获取Socket 对象,对象从beginsend 中的最后个参数上获得
Socket sock1 = (Socket)ar.AsyncState;
if (sock1.Connected)//如果连接还是有效
{
//这里建立一个委托
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
/*
* 此处为:开始接受数据(在发送完毕之后-->出自于上面的匿名委托),
* 当接收完信息之后,执行OnrecieveData 方法(由委托传进去),
* 注意,是异步调用
*/
sock1.BeginReceive(m_byBuff, , m_byBuff.Length, SocketFlags.None, recieveData, sock1);
}
}, s);
/*
* 结束异步发送
* EndSend 完成在BeginSend 中启动的异步发送操作。
* 在调用BeginSend 之前,需创建一个实现AsyncCallback 委托的回调方法。
* 该回调方法在单独的线程中执行并在BeginSend 返回后由系统调用。
* 回调方法必须接受BeginSend 方法所返回的IAsyncResult 作为参数。
*
* 在回调方法中,调用IAsyncResult 参数的AsyncState 方法可以获取发送Socket。
* 在获取Socket 之后,则可以调用EndSend 方法以成功完成发送操作,并返回发送的字节数。
*/
s.EndSend(ar2);
}
catch (Exception ers)
{
Console.WriteLine("出错了,在回发数据的时候:" + ers.Message);
}
}
#endregion /// <param name="str_origin">必要转换的字符串</param>
/// <returns>转换后的字符串</returns>
private string ConvertToGB2312(string str_origin)
{
char[] chars = str_origin.ToCharArray();
byte[] bytes = new byte[chars.Length];
for (int i = ; i < chars.Length; i++)
{
int c = (int)chars[i];
bytes[i] = (byte)c;
}
Encoding Encoding_GB2312 = Encoding.GetEncoding("GB2312");
string str_converted = Encoding_GB2312.GetString(bytes);
return str_converted;
} } }
二:Telnet类
文件名:TelnetClass.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading; namespace EmptyProjectNet40_FineUI.App_Code.Helper
{ // //调用方法如下:
//Telnet p = new Telnet("192.168.1.100", 23, 50); //if(p.Connect()==false)
//{
// Console.WriteLine("连接失败");
// return;
//}
////等待指定字符返回后才执行下一命令
//p.WaitFor("login:");
//p.Send("admin");
//p.WaitFor("password:");
//p.Send("123456");
//p.WaitFor(">");
////Console.WriteLine(p.SessionLog);
//Console.WriteLine(p.WorkingData);
//改进后代码(注意标蓝色的部分): public class Telnet
{
#region telnet的数据定义
/// <summary>
/// 标志符,代表是一个TELNET 指令
/// </summary>
readonly Char IAC = Convert.ToChar();
/// <summary>
/// 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
/// </summary>
readonly Char DO = Convert.ToChar();
/// <summary>
/// 表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。
/// </summary>
readonly Char DONT = Convert.ToChar();
/// <summary>
/// 表示希望开始使用或者确认所使用的是指定的选项。
/// </summary>
readonly Char WILL = Convert.ToChar();
/// <summary>
/// 表示拒绝使用或者继续使用指定的选项。
/// </summary>
readonly Char WONT = Convert.ToChar();
/// <summary>
/// 表示后面所跟的是对需要的选项的子谈判
/// </summary>
readonly Char SB = Convert.ToChar();
/// <summary>
/// 子谈判参数的结束
/// </summary>
readonly Char SE = Convert.ToChar();
const Char IS = '';
const Char SEND = '';
const Char INFO = '';
const Char VAR = '';
const Char VALUE = '';
const Char ESC = '';
const Char USERVAR = '';
/// <summary>
/// 流
/// /// </summary>
byte[] m_byBuff = new byte[];
/// <summary>
/// 收到的控制信息
/// </summary>
private ArrayList m_ListOptions = new ArrayList();
/// <summary>
/// 存储准备发送的信息
/// </summary>
string m_strResp;
/// <summary>
/// 一个Socket套接字
/// </summary>
private Socket s;
#endregion private IPEndPoint iep;
private string address;
private int port;
private int timeout; private string strWorkingData = ""; // 保存从服务器端接收到的数据
private string strFullLog = "";
//==== 夏春涛 扩充 20110531 ================================================ private string strWorkingDataX = "";
//用于获取当前工作的数据内容 public string WorkingData
{
get { return strWorkingDataX; }
}
//===================================================================
public Telnet(string Address, int Port, int CommandTimeout)
{
address = Address;
port = Port;
timeout = CommandTimeout;
} /// <summary>
/// 启动socket 进行telnet操作
/// </summary>
public bool Connect()
{ IPAddress import = GetIP(address);
//IPAddress import = address; s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); iep = new IPEndPoint(import, port); try
{
// Try a blocking connection to the server
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); s.Connect(iep); //异步回调
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
s.BeginReceive(m_byBuff, , m_byBuff.Length, SocketFlags.None, recieveData, s); return true;
}
catch (Exception)
{
return false;
}
} /// <summary>
/// 当接收完成后,执行的方法(供委托使用)
/// </summary>
/// <param name="ar"></param>
private void OnRecievedData(IAsyncResult ar)
{
try
{
//从参数中获得给的socket 对象
Socket sock = (Socket)ar.AsyncState; //EndReceive方法为结束挂起的异步读取
int nBytesRec = sock.EndReceive(ar);
//如果有接收到数据的话
if (nBytesRec > )
{
//声明一个字符串,用来存储解析过的字符串
string m_strLine = "";
//遍历Socket接收到的字符
/*
* 此循环用来调整linux 和 windows在换行上标记的区别
* 最后将调整好的字符赋予给 m_strLine
*/
for (int i = ; i < nBytesRec; i++)
{
Char ch = Convert.ToChar(m_byBuff[i]);
switch (ch)
{
case '\r':
m_strLine += Convert.ToString("\r\n");
break;
case '\n':
break;
default:
m_strLine += Convert.ToString(ch);
break;
}
}
try
{
//获得转义后的字符串的长度
int strLinelen = m_strLine.Length;
//如果长度为零
if (strLinelen == )
{
//则返回"\r\n" 即回车换行
m_strLine = Convert.ToString("\r\n");
}
//建立一个流,把接收的信息(转换后的)存进 mToProcess 中
Byte[] mToProcess = new Byte[strLinelen];
for (int i = ; i < strLinelen; i++)
mToProcess[i] = Convert.ToByte(m_strLine[i]);
//对接收的信息进行处理,包括对传输过来的信息的参数的存取和
string mOutText = ProcessOptions(mToProcess);
//==== 夏春涛 扩充 20110531 ==============================================
mOutText = ConvertToGB2312(mOutText);
strWorkingDataX = mOutText;
//===================================================================
//解析命令后返回 显示信息(即除掉了控制信息)
if (mOutText != "")
{
//Console.Write(mOutText);//显示输出//夏春涛 去掉 20110531/////////////////////////
strWorkingData = mOutText;
strFullLog += mOutText;
}
//接收完数据,处理完字符串数据等一系列事物之后,开始回发数据
RespondToOptions();
}
catch (Exception ex)
{
throw new Exception("接收数据的时候出错了! " + ex.Message);
}
}
else// 如果没有接收到任何数据的话
{
// 关闭连接
// 关闭socket
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
}
catch { }
}
/// <summary>
/// 发送数据的函数
/// </summary>
private void RespondToOptions()
{
try
{
//声明一个字符串,来存储 接收到的参数
string strOption;
/*
* 此处的控制信息参数,是之前接受到信息之后保存的
* 例如 255 253 23 等等
*/
for (int i = ; i < m_ListOptions.Count; i++)
{
//获得一个控制信息参数
strOption = (string)m_ListOptions[i];
//根据这个参数,进行处理
ArrangeReply(strOption);
}
DispatchMessage(m_strResp);
m_strResp = "";
m_ListOptions.Clear();
}
catch (Exception ers)
{
Console.WriteLine("出错了,在回发数据的时候 " + ers.Message); }
}
/// <summary>
/// 解析接收的数据,生成最终用户看到的有效文字,同时将附带的参数存储起来
///</summary>
///<param name="m_strLineToProcess">收到的处理后的数据</param>
/// <returns></returns>
private string ProcessOptions(byte[] m_strLineToProcess)
{
string m_DISPLAYTEXT = "";
string m_strTemp = "";
string m_strOption = "";
string m_strNormalText = "";
bool bScanDone = false;
int ndx = ;
int ldx = ;
char ch;
try
{
//把数据从byte[] 转化成string
for (int i = ; i < m_strLineToProcess.Length; i++)
{
Char ss = Convert.ToChar(m_strLineToProcess[i]);
m_strTemp = m_strTemp + Convert.ToString(ss);
} //此处意义为,当没描完数据前,执行扫描
while (bScanDone != true)
{
//获得长度
int lensmk = m_strTemp.Length;
//之后开始分析指令,因为每条指令为255 开头,故可以用此来区分出每条指令
ndx = m_strTemp.IndexOf(Convert.ToString(IAC));
//此处为出错判断,本无其他含义
if (ndx > lensmk)
ndx = m_strTemp.Length; //此处为,如果搜寻到IAC标记的telnet 指令,则执行以下步骤
if (ndx != -)
{
#region 如果存在IAC标志位
// 将 标志位IAC 的字符 赋值给最终显示文字
m_DISPLAYTEXT += m_strTemp.Substring(, ndx);
// 此处获得命令码
ch = m_strTemp[ndx + ];
//如果命令码是253(DO) 254(DONT) 521(WILL) 252(WONT) 的情况下
if (ch == DO || ch == DONT || ch == WILL || ch == WONT)
{ //将以IAC 开头3个字符组成的整个命令存储起来
m_strOption = m_strTemp.Substring(ndx, );
m_ListOptions.Add(m_strOption);
// 将 标志位IAC 的字符 赋值给最终显示文字
m_DISPLAYTEXT += m_strTemp.Substring(, ndx);
//将处理过的字符串删去
string txt = m_strTemp.Substring(ndx + );
m_strTemp = txt;
}
//如果IAC后面又跟了个IAC (255)
else if (ch == IAC)
{
//则显示从输入的字符串头开始,到之前的IAC 结束
m_DISPLAYTEXT = m_strTemp.Substring(, ndx);
//之后将处理过的字符串排除出去
m_strTemp = m_strTemp.Substring(ndx + );
}
//如果IAC后面跟的是SB(250)
else if (ch == SB)
{
m_DISPLAYTEXT = m_strTemp.Substring(, ndx);
ldx = m_strTemp.IndexOf(Convert.ToString(SE));
m_strOption = m_strTemp.Substring(ndx, ldx);
m_ListOptions.Add(m_strOption);
m_strTemp = m_strTemp.Substring(ldx);
}
#endregion
}
//若字符串里已经没有IAC标志位了
else
{ //显示信息累加上m_strTemp存储的字段
m_DISPLAYTEXT = m_DISPLAYTEXT + m_strTemp;
bScanDone = true;
}
}
//输出人看到的信息
m_strNormalText = m_DISPLAYTEXT;
}
catch (Exception eP)
{
throw new Exception("解析传入的字符串错误:" + eP.Message);
} return m_strNormalText;
}
/// <summary>
/// 获得IP地址
/// </summary>
/// <param name="import"></param>
/// <returns></returns>
private static IPAddress GetIP(string import)
{
IPHostEntry IPHost = Dns.GetHostEntry(import);
return IPHost.AddressList[];
} #region magic Function
//解析传过来的参数,生成回发的数据到m_strResp
private void ArrangeReply(string strOption)
{
try
{
Char Verb;
Char Option;
Char Modifier;
Char ch;
bool bDefined = false;
//排错选项,无啥意义
if (strOption.Length < ) return;
//获得命令码
Verb = strOption[];
//获得选项码
Option = strOption[];
//如果选项码为 回显(1) 或者是抑制继续进行(3)
if (Option == || Option == )
{
bDefined = true;
}
// 设置回发消息,首先为标志位255
m_strResp += IAC;
//如果选项码为 回显(1) 或者是抑制继续进行(3) ==true
if (bDefined == true)
{
#region 继续判断
//如果命令码为253 (DO)
if (Verb == DO)
{
//我设置我应答的命令码为 251(WILL) 即为支持 回显或抑制继续进行
ch = WILL;
m_strResp += ch;
m_strResp += Option;
}
//如果命令码为 254(DONT)
if (Verb == DONT)
{
//我设置我应答的命令码为 252(WONT) 即为我也会"拒绝启动" 回显或抑制继续进行
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
//如果命令码为251(WILL)
if (Verb == WILL)
{
//我设置我应答的命令码为 253(DO) 即为我认可你使用回显或抑制继续进行
ch = DO;
m_strResp += ch;
m_strResp += Option;
//break;
}
//如果接受到的命令码为251(WONT)
if (Verb == WONT)
{
//应答 我也拒绝选项请求回显或抑制继续进行
ch = DONT;
m_strResp += ch;
m_strResp += Option;
//break;
}
//如果接受到250(sb,标志子选项开始)
if (Verb == SB)
{
/*
* 因为启动了子标志位,命令长度扩展到了4字节,
* 取最后一个标志字节为选项码
* 如果这个选项码字节为1(send)
* 则回发为 250(SB子选项开始) + 获取的第二个字节 + 0(is) + 255(标志位IAC) + 240(SE子选项结束)
*/
Modifier = strOption[];
if (Modifier == SEND)
{
ch = SB;
m_strResp += ch;
m_strResp += Option;
m_strResp += IS;
m_strResp += IAC;
m_strResp += SE;
}
}
#endregion
}
else //如果选项码不是1 或者3
{
#region 底下一系列代表,无论你发那种请求,我都不干
if (Verb == DO)
{
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == DONT)
{
ch = WONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == WILL)
{
ch = DONT;
m_strResp += ch;
m_strResp += Option;
}
if (Verb == WONT)
{
ch = DONT;
m_strResp += ch;
m_strResp += Option;
}
#endregion
}
}
catch (Exception eeeee)
{
throw new Exception("解析参数时出错:" + eeeee.Message);
}
}
/// <summary>
/// 将信息转化成charp[] 流的形式,使用socket 进行发出
/// 发出结束之后,使用一个匿名委托,进行接收,
/// 之后这个委托里,又有个委托,意思是接受完了之后执行OnRecieveData 方法
///
/// </summary>
/// <param name="strText"></param>
void DispatchMessage(string strText)
{
try
{
//申请一个与字符串相当长度的char流
Byte[] smk = new Byte[strText.Length];
for (int i = ; i < strText.Length; i++)
{
//解析字符串,将其存储到char流中去
Byte ss = Convert.ToByte(strText[i]);
smk[i] = ss;
}
//发送char流,之后发送完毕后执行委托中的方法(此处为匿名委托)
IAsyncResult ar2 = s.BeginSend(smk, , smk.Length, SocketFlags.None, delegate(IAsyncResult ar)
{
//当执行完"发送数据" 这个动作后
// 获取Socket对象,对象从beginsend 中的最后个参数上获得
Socket sock1 = (Socket)ar.AsyncState;
if (sock1.Connected)//如果连接还是有效
{
//这里建立一个委托
AsyncCallback recieveData = new AsyncCallback(OnRecievedData); sock1.BeginReceive(m_byBuff, , m_byBuff.Length, SocketFlags.None, recieveData, sock1); }
}, s); s.EndSend(ar2);
}
catch (Exception ers)
{
Console.WriteLine("出错了,在回发数据的时候:" + ers.Message);
}
} /// <summary>
/// 等待指定的字符串返回
/// </summary>
/// <param name="DataToWaitFor">等待的字符串</param>
/// <returns>返回0</returns>
public int WaitFor(string DataToWaitFor)
{
long lngStart = DateTime.Now.AddSeconds(this.timeout).Ticks;
long lngCurTime = ; while (strWorkingData.ToLower().IndexOf(DataToWaitFor.ToLower()) == -)
{
lngCurTime = DateTime.Now.Ticks;
if (lngCurTime > lngStart)
{
throw new Exception("Timed Out waiting for : " + DataToWaitFor);
}
Thread.Sleep();
}
strWorkingData = "";
return ;
} public void Send(string message)
{
DispatchMessage(message);
//因为每发送一行都没有发送回车,故在此处补上
DispatchMessage("\r\n");
}
#endregion /// <summary>
/// 取完整日志
/// </summary>
public string SessionLog
{
get
{
return strFullLog;
}
} //======================================================================================
/// <summary>
/// 字符串编码转换,解决汉字显示乱码问题。 /// 原始字符串中的汉字存储的是汉字内码,此代码实质是将汉字内码转换为GB2312编码。(夏春涛20110531)
/// </summary>
/// <param name="str_origin">需要转换的字符串</param>
/// <returns>转换后的字符串</returns>
private string ConvertToGB2312(string str_origin)
{
char[] chars = str_origin.ToCharArray();
byte[] bytes = new byte[chars.Length];
for (int i = ; i < chars.Length; i++)
{
int c = (int)chars[i];
bytes[i] = (byte)c;
}
Encoding Encoding_GB2312 = Encoding.GetEncoding("GB2312");
string str_converted = Encoding_GB2312.GetString(bytes);
return str_converted;
}
//======================================================================================
}
}
三:Ctelnet.cs类
using System;
using System.Text;
using System.Net.Sockets;
using FineUI; /// <summary>
/// Summary description for ClassTelnet
/// </summary>
public class ClassTelnet
{
TcpClient telnet_tcp_client; public string strhost; // IP 地址
public string strusername; // username
public string strpassword; // password
private int ilogin_wait_time = ; //网络延迟等待时间
private int irecv_wait_time = ; //网络延迟等待时间 //Telnet protocal key
enum Verbs
{
WILL = ,
WONT = ,
DO = ,
DONT = ,
IAC =
}
public ClassTelnet()
{
}
/**
* Telnet 关闭连接
*/
public void close_telnet()
{
try
{
if (telnet_tcp_client == null)
{
return;
}
if (telnet_tcp_client.Connected)
{
telnet_tcp_client.Close();
}
}
catch (Exception ex)
{
//Consule.Write("异常");
Alert.Show("异常");
}
} /**
* Telnet连接到服务器
*/
public bool open_connect()
{
bool blresult;
string strtemp; blresult = true; try
{
// new socket
telnet_tcp_client = new TcpClient(this.strhost, ); System.Threading.Thread.Sleep(ilogin_wait_time);
// read host info data
strtemp = recv_data_from_host();
//strtemp = ConvertToGB2312(strtemp);
blresult = strtemp.TrimEnd().EndsWith(":");
if (blresult == false)
{
Alert.Show("read host info data error");
return blresult;
} // username send to host
blresult = send_data_to_host(this.strusername + "/n/r");
if (blresult == false)
{
Alert.Show("username send error");
return blresult;
} System.Threading.Thread.Sleep(ilogin_wait_time);
strtemp = recv_data_from_host();
blresult = strtemp.TrimEnd().EndsWith(":");
if (blresult == false)
{
return blresult;
} // password send to host
blresult = send_data_to_host(this.strpassword + "/n/r");
if (blresult == false)
{
return blresult;
}
System.Threading.Thread.Sleep(ilogin_wait_time);
strtemp = recv_data_from_host();
if ((strtemp.Trim().LastIndexOf("#") > -) ||
(strtemp.Trim().LastIndexOf("$") > -) ||
(strtemp.Trim().LastIndexOf(">") > -))
{
blresult = true;
}
else
{
blresult = false;
}
}
catch (Exception ex)
{
blresult = false;
}
return blresult;
} /**
* 执行命令
*/
public bool exec_command(string strcmd)
{
bool blresult;
string strprompt; blresult = false;
strprompt = ""; if (telnet_tcp_client.Connected)
{
blresult = send_data_to_host(strcmd + "/n/r");
if (blresult == false)
{
return false;
}
strprompt = ""; strprompt = recv_data_from_host(); if ((strprompt.Trim().LastIndexOf("#") > -) ||
(strprompt.Trim().LastIndexOf("$") > -) ||
(strprompt.Trim().LastIndexOf(">") > -))
{
blresult = true;
return blresult;
}
}
return blresult;
} /**
* telnet向主机发送数据
*/
public bool send_data_to_host(string strcmd)
{
try
{
// socket error时、return
if (!telnet_tcp_client.Connected)
{
return false;
} byte[] bbuf = System.Text.ASCIIEncoding.ASCII.GetBytes(strcmd.Replace("/0xFF", "/0xFF/0xFF")); telnet_tcp_client.GetStream().Write(bbuf, , bbuf.Length);
}
catch (Exception ex)
{
return false;
}
return true;
} /**
* Telnet从主机接受数据
*/
public string recv_data_from_host()
{
int iinput_data; //data
int inputverb;
int inputoption;
StringBuilder sbtemp;
NetworkStream ns_temp;
byte[] bread_buffer;
StringBuilder sbcomplete_message;
int iread_bytes_num; sbtemp = new StringBuilder(); // socket没有连接的时候,返回空
if (!telnet_tcp_client.Connected)
{
return null;
} do
{
// read 1 byte
iinput_data = telnet_tcp_client.GetStream().ReadByte();
switch (iinput_data)
{
case -:
break;
case (int)Verbs.IAC: // 接受的数据有keyword // read 1 byte
inputverb = telnet_tcp_client.GetStream().ReadByte();
if (inputverb == -) break;
switch (inputverb)
{
case (int)Verbs.IAC:
sbtemp.Append(inputverb);
break;
case (int)Verbs.DO:
case (int)Verbs.DONT:
case (int)Verbs.WILL:
case (int)Verbs.WONT:
inputoption = telnet_tcp_client.GetStream().ReadByte();
if (inputoption == -) break;
telnet_tcp_client.GetStream().WriteByte((byte)Verbs.IAC);
telnet_tcp_client.GetStream().WriteByte(inputverb ==
(int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
telnet_tcp_client.GetStream().WriteByte((byte)inputoption);
break;
default:
break;
}
break;
default:
sbtemp.Append((char)iinput_data);
bread_buffer = new byte[];
sbcomplete_message = new StringBuilder();
iread_bytes_num = ;
ns_temp = telnet_tcp_client.GetStream();
if (ns_temp.CanRead)
{
System.Threading.Thread.Sleep(ilogin_wait_time);
iread_bytes_num = ns_temp.Read(bread_buffer, , bread_buffer.Length);
sbtemp.AppendFormat("{0}", Encoding.ASCII.GetString(bread_buffer,
, iread_bytes_num));
}
break;
} // timeout
System.Threading.Thread.Sleep(irecv_wait_time);
} while (telnet_tcp_client.Available > ); // 返回接受的数据
return sbtemp.ToString();
} /**
* 例子程序
*/
public bool exec_sample()
{
bool blsts;
blsts = true; // 关闭Telnet连接
this.close_telnet(); // telnet连接到远程主机
blsts = this.open_connect();
if (blsts == false)
{
return blsts;
} // 在远程主机上执行命令
blsts = this.exec_command("echo ABC");
// 执行失败
if (blsts == false)
{
Alert.Show("命令执行失败");
}
return blsts;
}
//======================================================================================
/// <summary>
/// 字符串编码转换,解决汉字显示乱码问题。 /// 原始字符串中的汉字存储的是汉字内码,此代码实质是将汉字内码转换为GB2312编码。(夏春涛20110531)
/// </summary>
/// <param name="str_origin">需要转换的字符串</param>
/// <returns>转换后的字符串</returns>
private string ConvertToGB2312(string str_origin)
{
char[] chars = str_origin.ToCharArray();
byte[] bytes = new byte[chars.Length];
for (int i = ; i < chars.Length; i++)
{
int c = (int)chars[i];
bytes[i] = (byte)c;
}
Encoding Encoding_GB2312 = Encoding.GetEncoding("GB2312");
string str_converted = Encoding_GB2312.GetString(bytes);
return str_converted;
}
//====================================================================================== }
三个Telnet链接类----来自网络的更多相关文章
- C#可扩展编程之MEF学习笔记(三):导出类的方法和属性
前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...
- 35 网络相关函数(三)——live555源码阅读(四)网络
35 网络相关函数(三)——live555源码阅读(四)网络 35 网络相关函数(三)——live555源码阅读(四)网络 简介 5)NoReuse不重用地址类 6)initializeWinsock ...
- 三分钟PJ隐藏SSID无线网络
一般来说用户可以通过路由或主机设置来隐藏无线信号的SSID网络信息,在这种情况下我们使用XP系统自带的无线信号扫描工具将看不到该无线网络的踪影,在这种情况下XP系统无线信号管理工具只能够看到将SSID ...
- “全栈2019”Java第三十八章:类与方法
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第三十七章:类与字段
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- telnet指令研究—以网络聊天程序为例
一.telnet指令 Telnet取名自Telecommunications和Networks的联合缩写,是早期个人计算机上连接到服务器主机的一个网络指令,由于存在安全问题,现在已经很少被使用.在wi ...
- 文件读写(三)利用FileStream类操作字节数组byte[]、BinaryFormatter、内存流MemoryStream
一.Stream类概述 在.NET Framework中,文件和流是有区别的.文件是存储在磁盘上的数据集,它具有名称和相应的路径.当打开一个文件并对其进行读/写时,该文件就称为流(stream).但是 ...
- 封装一个MongoDB的 asp.net 链接类
using System; using System.Collections.Generic; using System.Linq; using MongoDB; /// <summary> ...
- PHP数据库链接类(PDO+Access)实例分享
这篇文章主要介绍了PHP数据库链接类(PDO+Access),有需要的朋友可以参考一下 PHP PDO Access链接 复制代码代码如下: class DbHelpClass { ...
随机推荐
- python3给socket模块设置代理
最近需要在公司学习socket编程,但是不能直接连接外网,需要设置一个代理才能正常访问.报错示例: import socket def blocking(wd): sock = socket.sock ...
- 《Maven实战》第5章 坐标和依赖
5.1 Maven坐标——项目唯一标识 groupId(必须定义):定义Mavan项目隶属的实际项目,如SpringFramework,一个实际项目可包含多个Maven项目 artifactId(必须 ...
- ()IT 职场经验)一位10年Java工作经验的架构师的经验分享,感觉很受用。
阿里巴巴技术大牛黄勇的经验分享,感觉很受用. 关于IT 职场经验 1. 把技术当成工具 技术这东西,其实一点都不神秘,它只不过是一个工具,用这个工具可以帮助我们解决实际问题,就这么简单. 我们每天在面 ...
- notepad++使用正则表达式的查找替换
使用正则表达式可以很好地完成很多繁琐耗时的工作,以下抄录editplus正则表达式的使用,同样适用于notepad++:表达式 说明\t 制表符.\n 新行.. 匹配任意字符.| 匹配表达式左边和右边 ...
- spring注解方式注入bean
用注解的方式注入bean,spring的配置文件也要增加一些约束和导入注解所在的包 applicationContext.xml <?xml version="1.0" en ...
- Codeforces 9C Hexadecimal's Numbers - 有技巧的枚举
2017-08-01 21:35:53 writer:pprp 集训第一天:作为第一道题来讲,说了两种算法, 第一种是跟二进制数联系起来进行分析: 第二种是用深度搜索来做,虽然接触过深度搜索但是这种题 ...
- Java对象初始化
自动初始化(默认值) 一个类的所有基本数据成员都会得到初始化,运行下面的例子可以查看这些默认值: class Default{ boolean t; char c; byte b; short s; ...
- 报错 IllegalArgumentException occurred calling getter of cn.itcast.entity.Customer.cid
我碰到这个问题的时候,没有数据类型不匹配的情况,也没有表达无法向action传递数据的情况,一直报这样的错误,意思就是无法使用Customer中的get方法来赋值.完整报错如下所示: HTTP Sta ...
- 安装(解密)win10 10074 esd 更新 10162 esd
最新ESD:http://ms-vnext.net/Win10esds/ 公开下载:http://ms-vnext.net/Win10esds/urls/ ----------------更新 --- ...
- java多线程学习三
本章主要学习线程的静态方法 1.先忙先看一段代码: public class MyThread3 implements Runnable { static { System.out.println(& ...