telnetC#.docx

上传人:b****6 文档编号:3639635 上传时间:2022-11-24 格式:DOCX 页数:25 大小:23.95KB
下载 相关 举报
telnetC#.docx_第1页
第1页 / 共25页
telnetC#.docx_第2页
第2页 / 共25页
telnetC#.docx_第3页
第3页 / 共25页
telnetC#.docx_第4页
第4页 / 共25页
telnetC#.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

telnetC#.docx

《telnetC#.docx》由会员分享,可在线阅读,更多相关《telnetC#.docx(25页珍藏版)》请在冰豆网上搜索。

telnetC#.docx

telnetC#

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.Net;

usingSystem.Net.Sockets;

usingSystem.Collections;

 

namespaceConsoleApplication1

{

publicclassProgram

{

#region一些telnet的数据定义,先没看懂没关系

///

///标志符,代表是一个TELNET指令

///

readonlyCharIAC=Convert.ToChar(255);

///

///表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。

///

readonlyCharDO=Convert.ToChar(253);

///

///表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。

///

readonlyCharDONT=Convert.ToChar(254);

///

///表示希望开始使用或者确认所使用的是指定的选项。

///

readonlyCharWILL=Convert.ToChar(251);

///

///表示拒绝使用或者继续使用指定的选项。

///

readonlyCharWONT=Convert.ToChar(252);

 

///

///表示后面所跟的是对需要的选项的子谈判

///

readonlyCharSB=Convert.ToChar(250);

 

///

///子谈判参数的结束

///

readonlyCharSE=Convert.ToChar(240);

 

constCharIS='0';

 

constCharSEND='1';

 

constCharINFO='2';

 

constCharVAR='0';

 

constCharVALUE='1';

 

constCharESC='2';

 

constCharUSERVAR='3';

 

///

///流

///

byte[]m_byBuff=newbyte[100000];

 

///

///收到的控制信息

///

privateArrayListm_ListOptions=newArrayList();

 

///

///存储准备发送的信息

///

stringm_strResp;

 

///

///一个Socket套接字

///

privateSockets;

#endregion

 

 

///

///主函数

///

///

staticvoidMain(string[]args)

{

//实例化这个对象

Programp=newProgram();

//启动socket进行telnet链接

p.doSocket();

 

 

}

 

///

///启动socket进行telnet操作

///

privatevoiddoSocket()

{

//获得链接的地址,可以是网址也可以是IP

Console.WriteLine("ServerAddress:

");

//解析输入,如果是一个网址,则解析成ip

IPAddressimport=GetIP(Console.ReadLine());

//获得端口号

Console.WriteLine("ServerPort:

");

intport=int.Parse(Console.ReadLine());

 

//建立一个socket对象,使用IPV4,使用流进行连接,使用tcp/ip协议

s=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

 

//获得一个链接地址对象(由IP地址和端口号构成)

IPEndPointaddress=newIPEndPoint(import,port);

 

/*

*说明此socket不是处于阻止模式

*

*msdn对阻止模式的解释:

*============================================================

*如果当前处于阻止模式,并且进行了一个并不立即完成的方法调用,

*则应用程序将阻止执行,直到请求的操作完成后才解除阻止。

*如果希望在请求的操作尚未完成的情况下也可以继续执行,

*请将Blocking属性更改为false。

Blocking属性对异步方法无效。

*如果当前正在异步发送和接收数据,并希望阻止执行,

*请使用ManualResetEvent类。

*============================================================

*/

s.Blocking=false;

 

/*

*开始一个对远程主机连接的异步请求,

*因为Telnet使用的是TCP链接,是面向连接的,

*所以此处BeginConnect会启动一个异步请求,

*请求获得与给的address的连接

*

*此方法的第二个函数是一个类型为AsyncCallback的委托

*

*这个AsyncCallbackmsdn给出的定义如下

*===================================================================

*使用AsyncCallback委托在一个单独的线程中处理异步操作的结果。

A

*syncCallback委托表示在异步操作完成时调用的回调方法。

*回调方法采用IAsyncResult参数,该参数随后可用来获取异步操作的结果。

*===================================================================

*这个方法里的委托实际上就是当异步请求有回应了之后,执行委托的方法.

*委托里的参数,实际上就是BeginConnect的第三个参数,

*此处为socket本身

*

*我比较懒,写了一个匿名委托,实际上跟AsyncCallback效果一个样.

*

*/

s.BeginConnect(

address,

delegate(IAsyncResultar)

/*

*此处为一个匿名委托,

*实际上等于

*建立一个AsyncCallback对象,指定后在此引用一个道理

*

*ok这里的意义是,

*当远程主机连接的异步请求有响应的时候,执行以下语句

*/

{

try

{

//获得传入的对象(此处对象是BeginConnect的第三个参数)

Socketsock1=(Socket)ar.AsyncState;

 

/*

*如果Socket在最近操作时连接到远程资源,则为true;否则为false。

*

*以下是MSDN对Connected属性的备注信息

*=========================================================================

*Connected属性获取截止到最后的I/O操作时Socket的连接状态。

*当它返回false时,表明Socket要么从未连接,要么已断开连接。

*

*Connected属性的值反映最近操作时的连接状态。

如果您需要确定连接的当前状态,

*请进行非阻止、零字节的Send调用。

*如果该调用成功返回或引发WAEWOULDBLOCK错误代码(10035),

*则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。

*=========================================================================

*/

if(sock1.Connected)

{

 

AsyncCallbackrecieveData=newAsyncCallback(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,0,m_byBuff.Length,SocketFlags.None,recieveData,sock1);

}

}

catch(Exceptionex)

{

Console.WriteLine("初始化接收信息出错:

"+ex.Message);

}

},

s);

 

//此处是为了发送指令而不停的循环

while(true)

{

//发送读出的数据

DispatchMessage(Console.ReadLine());

//因为每发送一行都没有发送回车,故在此处补上

DispatchMessage("/r/n");

}

 

}

 

///

///当接收完成后,执行的方法(供委托使用)

///

///

privatevoidOnRecievedData(IAsyncResultar)

{

//从参数中获得给的socket对象

Socketsock=(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方法。

*=========================================================================================

*/

intnBytesRec=sock.EndReceive(ar);

//如果有接收到数据的话

if(nBytesRec>0)

{

//将接收到的数据转个码,顺便转成string型

stringsRecieved=Encoding.GetEncoding("utf-8").GetString(m_byBuff,0,nBytesRec);

 

//声明一个字符串,用来存储解析过的字符串

stringm_strLine="";

//遍历Socket接收到的字符

 

/*

*此循环用来调整linux和windows在换行上标记的区别

*最后将调整好的字符赋予给m_strLine

*/

for(inti=0;i

{

Charch=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

{

//获得转义后的字符串的长度

intstrLinelen=m_strLine.Length;

//如果长度为零

if(strLinelen==0)

{

//则返回"/r/n"即回车换行

m_strLine=Convert.ToString("/r/n");

}

 

//建立一个流,把接收的信息(转换后的)存进mToProcess中

Byte[]mToProcess=newByte[strLinelen];

for(inti=0;i

mToProcess[i]=Convert.ToByte(m_strLine[i]);

 

//Processtheincomingdata

//对接收的信息进行处理,包括对传输过来的信息的参数的存取和

stringmOutText=ProcessOptions(mToProcess);

//解析命令后返回显示信息(即除掉了控制信息)

if(mOutText!

="")

Console.Write(mOutText);

 

 

//Respondtoanyincomingcommands

//接收完数据,处理完字符串数据等一系列事物之后,开始回发数据

RespondToOptions();

}

catch(Exceptionex)

{

thrownewException("接收数据的时候出错了!

"+ex.Message);

}

}

else//如果没有接收到任何数据的话

{

//输出关闭连接

Console.WriteLine("Disconnected",sock.RemoteEndPoint);

//关闭socket

sock.Shutdown(SocketShutdown.Both);

sock.Close();

Console.Write("GameOver");

Console.ReadLine();

}

}

 

///

///发送数据的函数

///

 

privatevoidRespondToOptions()

{

try

{

//声明一个字符串,来存储接收到的参数

stringstrOption;

/*

*此处的控制信息参数,是之前接受到信息之后保存的

*例如25525323等等

*具体参数的含义需要去查telnet协议

*/

for(inti=0;i

{

//获得一个控制信息参数

strOption=(string)m_ListOptions[i];

//根据这个参数,进行处理

ArrangeReply(strOption);

}

DispatchMessage(m_strResp);

m_strResp="";

m_ListOptions.Clear();

}

catch(Exceptioners)

{

Console.WriteLine("错错了,在回发数据的时候"+ers.Message);

}

}

 

///

///解析接收的数据,生成最终用户看到的有效文字,同时将附带的参数存储起来

///

///收到的处理后的数据

///

privatestringProcessOptions(byte[]m_strLineToProcess)

{

 

stringm_DISPLAYTEXT="";

stringm_strTemp="";

stringm_strOption="";

stringm_strNormalText="";

boolbScanDone=false;

intndx=0;

intldx=0;

charch;

try

{

//把数据从byte[]转化成string

for(inti=0;i

{

Charss=Convert.ToChar(m_strLineToProcess[i]);

m_strTemp=m_strTemp+Convert.ToString(ss);

}

 

//此处意义为,当没描完数据前,执行扫描

while(bScanDone!

=true)

{

//获得长度

intlensmk=m_strTemp.Length;

//之后开始分析指令,因为每条指令为255开头,故可以用此来区分出每条指令

ndx=m_strTemp.IndexOf(Convert.ToString(IAC));

 

//此处为出错判断,本无其他含义

if(ndx>lensmk)

ndx=m_strTemp.Length;

 

//此处为,如果搜寻到IAC标记的telnet指令,则执行以下步骤

if(ndx!

=-1)

{

#region如果存在IAC标志位

//将标志位IAC的字符赋值给最终显示文字

m_DISPLAYTEXT+=m_strTemp.Substring(0,ndx);

//此处获得命令码

ch=m_strTemp[ndx+1];

 

//如果命令码是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,3);

m_ListOptions.Add(m_strOption);

 

//将标志位IAC的字符赋值给最终显示文字

m_DISPLAYTEXT+=m_strTemp.Substring(0,ndx);

 

//将处理过的字符串删去

stringtxt=m_strTemp.Substring(ndx+3);

m_strTemp=txt;

}

//如果IAC后面又跟了个IAC(255)

elseif(ch==IAC)

{

//则显示从输入的字符串头开始,到之前的IAC结束

m_DISPLAYTEXT=m_strTemp.Substring(0,ndx);

//之后将处理过的字符串排除出去

m_strTemp=m_strTemp.Substring(ndx+1);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1