Socket实现telnet交互通信
来源:互联网 发布:淘宝巫师鞋柜是正品吗 编辑:程序博客网 时间:2024/06/18 11:20
using System;
usingSystem.Collections.Generic;
using System.Text;
using System.Net;
usingSystem.Net.Sockets;
usingSystem.Collections;
using System.Threading;
namespace TelnetDemo
{
public class Telnet
{
#region telnet的数据定义
// 标志符,代表是一个TELNET 指令
readonly Char IAC = Convert.ToChar(255);
// 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
readonly Char DO = Convert.ToChar(253);
// 表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。
readonly Char DONT = Convert.ToChar(254);
// 表示希望开始使用或者确认所使用的是指定的选项。
readonly Char WILL = Convert.ToChar(251);
// 表示拒绝使用或者继续使用指定的选项。
readonly Char WONT = Convert.ToChar(252);
// 表示后面所跟的是对需要的选项的子谈判
readonly Char SB = Convert.ToChar(250);
// 子谈判参数的结束
readonly Char SE = Convert.ToChar(240);
const Char IS = '0';
const Char SEND = '1';
const Char INFO = '2';
const Char VAR = '0';
const Char VALUE = '1';
const Char ESC = '2';
const Char USERVAR = '3';
// 流
byte[] m_byBuff = new byte[100000];
// 收到的控制信息
private ArrayList m_ListOptions = new ArrayList();
// 存储准备发送的信息
string m_strResp;
// 一个Socket套接字
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, intCommandTimeout)
{
address = Address;
port = Port;
timeout = CommandTimeout;
}
///
/// 启动socket进行telnet操作
///
public bool Connect()
{
IPAddress import = GetIP(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 = newAsyncCallback(OnRecievedData);
s.BeginReceive(m_byBuff, 0, m_byBuff.Length, SocketFlags.None,recieveData, s);
return true;
}
catch (Exception)
{
return false;
}
}
///
///当接收完成后,执行的方法(供委托使用)
///
///
private void OnRecievedData(IAsyncResult ar)
{
try
{
//从参数中获得给的socket对象
Socket sock = (Socket)ar.AsyncState;
//EndReceive方法为结束挂起的异步读取
int nBytesRec = sock.EndReceive(ar);
//如果有接收到数据的话
if (nBytesRec > 0)
{
//声明一个字符串,用来存储解析过的字符串
string m_strLine = "";
//遍历Socket接收到的字符
for (int i = 0; i < nBytesRec; i++)
{
Char ch = Convert.ToChar(m_byBuff);
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 == 0)
{
//则返回"\r\n"即回车换行
m_strLine = Convert.ToString("\r\n");
}
//建立一个流,把接收的信息(转换后的)存进 mToProcess中
Byte[] mToProcess = new Byte[strLinelen];
for (int i = 0; i < strLinelen; i++)
mToProcess = Convert.ToByte(m_strLine);
//对接收的信息进行处理,包括对传输过来的信息的参数的存取和
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 { }
}
///
/// 发送数据的函数
///
private void RespondToOptions()
{
try
{
//声明一个字符串,来存储接收到的参数
string strOption;
for (int i = 0; i < m_ListOptions.Count; i++)
{
//获得一个控制信息参数
strOption = (string)m_ListOptions;
//根据这个参数,进行处理
ArrangeReply(strOption);
}
DispatchMessage(m_strResp);
m_strResp = "";
m_ListOptions.Clear();
}
catch (Exception ers)
{
Console.WriteLine("出错了,在回发数据的时候 " + ers.Message);
}
}
///
///解析接收的数据,生成最终用户看到的有效文字,同时将附带的参数存储起来
///
///收到的处理后的数据
///
private string ProcessOptions(byte[]m_strLineToProcess)
{
string m_DISPLAYTEXT = "";
string m_strTemp = "";
string m_strOption = "";
string m_strNormalText = "";
bool bScanDone = false;
int ndx = 0;
int ldx = 0;
char ch;
try
{
//把数据从byte[]转化成string
for (int i = 0; i < m_strLineToProcess.Length; i++)
{
Char ss = Convert.ToChar(m_strLineToProcess);
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 != -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);
//将处理过的字符串删去
string txt = m_strTemp.Substring(ndx + 3);
m_strTemp = txt;
}
//如果IAC后面又跟了个IAC(255)
else if (ch == IAC)
{
//则显示从输入的字符串头开始,到之前的IAC结束
m_DISPLAYTEXT = m_strTemp.Substring(0, ndx);
//之后将处理过的字符串排除出去
m_strTemp = m_strTemp.Substring(ndx + 1);
}
//如果IAC后面跟的是SB(250)
else if (ch == SB)
{
m_DISPLAYTEXT = m_strTemp.Substring(0, 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;
}
///
///获得IP地址
///
///
///
private static IPAddress GetIP(string import)
{
IPHostEntry IPHost = Dns.GetHostEntry(import);
return IPHost.AddressList[0];
}
#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 < 3) return;
//获得命令码
Verb = strOption;
//获得选项码
Option = strOption;
//如果选项码为 回显(1) 或者是抑制继续进行(3)
if (Option == 1 || Option == 3)
{
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)
{
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);
}
}
///
/// 将信息转化成charp[] 流的形式,使用socket进行发出
///发出结束之后,使用一个匿名委托,进行接收,
/// 之后这个委托里,又有个委托,意思是接受完了之后执行OnRecieveData方法
///
///
///
void DispatchMessage(string strText)
{
try
{
//申请一个与字符串相当长度的char流
Byte[] smk = new Byte[strText.Length];
for (int i = 0; i < strText.Length; i++)
{
//解析字符串,将其存储到char流中去
Byte ss = Convert.ToByte(strText);
smk = ss;
}
//发送char流,之后发送完毕后执行委托中的方法(此处为匿名委托)
IAsyncResult ar2 = s.BeginSend(smk, 0, smk.Length,SocketFlags.None, delegate(IAsyncResult ar)
{
//当执行完"发送数据"这个动作后
// 获取Socket对象,对象从beginsend中的最后个参数上获得
Socket sock1 = (Socket)ar.AsyncState;
if(sock1.Connected)//如果连接还是有效
{
//这里建立一个委托
AsyncCallback recieveData = newAsyncCallback(OnRecievedData);
sock1.BeginReceive(m_byBuff, 0, m_byBuff.Length, SocketFlags.None,recieveData, sock1);
}
}, s);
s.EndSend(ar2);
}
catch (Exception ers)
{
Console.WriteLine("出错了,在回发数据的时候:" + ers.Message);
}
}
///
/// 等待指定的字符串返回
///
/// 等待的字符串
/// 返回0
public int WaitFor(string DataToWaitFor)
{
long lngStart =DateTime.Now.AddSeconds(this.timeout).Ticks;
long lngCurTime = 0;
while (strWorkingData.ToLower().IndexOf(DataToWaitFor.ToLower()) ==-1)
{
lngCurTime = DateTime.Now.Ticks;
if (lngCurTime > lngStart)
{
throw new Exception("Timed Out waiting for : " +DataToWaitFor);
}
Thread.Sleep(1);
}
strWorkingData = "";
return 0;
}
public void Send(string message)
{
DispatchMessage(message);
//因为每发送一行都没有发送回车,故在此处补上
DispatchMessage("\r\n");
}
#endregion
///
/// 取完整日志
///
public string SessionLog
{
get
{
return strFullLog;
}
}
private string ConvertToGB2312(string str_origin)
{
char[] chars = str_origin.ToCharArray();
byte[] bytes = new byte[chars.Length];
for (int i = 0; i < chars.Length; i++)
{
int c = (int)chars;
bytes = (byte)c;
}
Encoding Encoding_GB2312 =Encoding.GetEncoding("GB2312");
string str_converted =Encoding_GB2312.GetString(bytes);
return str_converted;
}
}
}
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.WorkingData);
- Socket实现telnet交互通信
- 用Socket实现程序之间的交互(通信)
- C#Socket实现telnet功能
- Linux环境下的c语言socket编程实现交互通信
- Socket通信,实现单客户端和服务器交互的C/S结构
- 基于socket用java实现telnet功能
- Java客户端C++服务端Socket交互通信
- socket通信:C#实现Socket通信
- 简单实现Socket通信
- C#实现socket通信
- C#实现Socket通信
- socket 实现即时通信
- Socket编程,实现通信
- android 实现socket通信
- java通信socket实现
- Socket实现简单通信
- socket通信实现
- javanio 实现socket通信
- BZOJ3207: 花神的嘲讽计划Ⅰ
- 【NOIP2012】 CODE[VS] 1217 借教室(线段树维护区间最小值)
- VB中 variant与object区别?
- 【NOI 2001】codevs1074 食物链
- 终年32岁的传奇数学家,生前寂寂无闻,一个世纪后却让硅谷领袖们集体落泪致敬
- Socket实现telnet交互通信
- BZOJ3208: 花神的秒题计划Ⅰ
- java基础-嵌套类
- [Sqoop]Sqoop安装
- boost中的shared_ptr
- setAttribute 和 getAttribute区别
- "把一个div标签,给它的属性设置position: fixed;bottom:0;固定在浏览器的最底部。 这个div标签在浏览器上下滚动的时候,会一直保持在屏幕最底部,这一点没有问题。但问题是当浏览
- Unity3D开发基础知识详解
- Oracle恢复到某个时间点的