//telnet 的命令格式:IAC+命令码+选项码
final byte IAC=(byte)255;
//协商的命令码
final byte DONT=(byte)254;
final byte DO=(byte)253;
final byte WONT=(byte)252;
final byte WILL=(byte)251;
final byte SB=(byte)250;
final byte SE=(byte)240;
//协商的选项码
final char IS = '0';
final char SEND = '1';
final char INFO = '2';
final char VAR = '0';
final char VALUE = '1';
final char ESC = '2';
final char USERVAR = '3';
final int MAX=1000000;
Socket s;
InputStream in;
OutputStream out;
PrintStream ps;
DataInputStream conIn;
BufferedInputStream dataIn;
// String sysIn="open\r\n";
byte[] recvByte; //接收的字节数据
String recv; //转换后的字符
byte[] sendByte; //发送的字节数据
String send; //发送的源字符
int read; //接收的字节数据的个数
int write; //发送的字节数据个数
boolean hasData; //标志套接字中的输入流是否还有未读完的数据
String ip;
int port;
public Socket2Telnet(Socket s,String ip,int port){
this.s=s;
this.ip=ip;
this.port=port;
}
//关闭socket连接
public void closeConnection(Socket s,InputStream in,OutputStream out){
if(s.isConnected()&&!s.isClosed()){
try {
in.close();
out.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//解析协商数据
public void Compile(){
//存在协商控制命令选项时需要解析并应答
write=0;
for(int i=0;i<read;){
if(recvByte[i]==IAC){ //255
// System.out.println("get IAC!"+(int)(recvByte[0]& 0xff)+recvByte[0]);
sendByte[write]=recvByte[i];
if(recvByte[i+2]==1||recvByte[i+2]==3){
if(recvByte[i+1]==DO){ //253
// System.out.println("get DO!"+(int)(recvByte[1]& 0xff));
sendByte[write+1]=WILL;
sendByte[write+2]=recvByte[i+2];
write+=3;
i+=3;
}else
if(recvByte[i+1]==WILL){ //251
// System.out.println("get WILL !"+(int)(recvByte[1]& 0xff)+recvByte[1]);
sendByte[write+1]=DO;
sendByte[write+2]=recvByte[i+2];
write+=3;
i+=3;
}else
if(recvByte[i+1]==WONT){ //252
// System.out.println("get WONT!"+(int)(recvByte[1]&0xff)+recvByte[1]);
sendByte[write+1]=DONT;
sendByte[write+2]=recvByte[i+2];
write+=3;
i+=3;
}else
if(recvByte[i+1]==DONT){ //254
// System.out.println("get DONT! "+(int)(recvByte[1]&0xff)+recvByte[1]);
sendByte[write+1]=WONT;
sendByte[write+2]=recvByte[i+2];
write+=3;
i+=3;
}else
if(recvByte[i+1]==SB){ //250
System.out.println("get SB ! "+(int)(recvByte[1]&0xff)+recvByte[1]);
if(recvByte[i+3]==SEND){
System.out.println("get SEND!"+recvByte[3]);
sendByte[write+1]=recvByte[i+1];
sendByte[write+2]=recvByte[i+2];
sendByte[write+3]=IS;
sendByte[write+4]=IAC;
sendByte[write+5]=SE;
System.out.println("YES, get a SD and SEND !");
write+=6;
i+=3;
}
}
// System.out.println(" and recvByte[2] "+(int)(recvByte[2]&0xff)+recvByte[2]+(char)(recvByte[2]&0xff));
// ps.write(sendByte,0,write);
// ps.flush();
}else{
if(recvByte[i+1]==DONT||recvByte[i+1]==DO){
sendByte[write+1]=WONT;
sendByte[write+2]=recvByte[i+2];
}
else if(recvByte[i+1]==WILL||recvByte[i+1]==WONT){
sendByte[write+1]=DONT;
sendByte[write+2]=recvByte[i+2];
}
write+=3;
i+=3;
}
}else{
return;
}
}
}
//sokcet连接服务器,收发数据
public void run(){
try {
s.connect(new InetSocketAddress(ip,port));
System.out.println("socket Connect success!");
System.out.println("Server IP:"+s.getInetAddress()+",port :"+s.getPort()+"\n");
//获取套接字的输入和输出流
in=s.getInputStream();
out=s.getOutputStream ();
conIn=new DataInputStream(System.in);
dataIn=new BufferedInputStream(in);
ps=new PrintStream(out);
//初始化
recvByte=new byte[MAX];
sendByte=new byte[MAX];
recv=new String("");
send=new String("");
write=read=0;
while(true){
read=write=0;
Thread.sleep(2000);
if((read=in.read(recvByte))>0){
hasData=true;
}else
hasData=false;
// System.out.println("recv data "+read+" byte!");
// System.out.println("recv msg :"+new String(recvByte,"UTF-8"));
// for(int i=0;i<read;i++)
// System.out.print((char)(recvByte[i]&0xff));
// System.out.println("");
for(int i=0;i<read;i++)
System.out.print((int)(recvByte[i]&0xff)+" ");
System.out.println("\n");
//协商的应答
if(read>0){
Compile();
if(write>0){
ps.write(sendByte,0,write);
// ps.flush();
}
}
System.out.println("read = "+read+",write = "+write);
Thread.sleep(3000);
//服务器没有响应时,等待用户输入命令;
//服务器返回输入命令时,告知用户命令,并读取用户输入并发送给服务器;
send="";
if(read<=0||read>write){
System.out.println(read>0?"recv msg:"+new String(recvByte,write,read-write,"UTF-8"):"");
if(read==2) System.out.println("recv two data:"+(recvByte[0]&0xff)+(recvByte[1]&0xff));
Scanner sc=new Scanner(System.in);
send=sc.nextLine()+"\r\n";
// send=conIn.readLine()+"\r\n";
if("exit".equals(send)){
closeConnection(s,in,out);
return;
}
System.out.println("send msg :"+send);
ps.write(send.getBytes("ISO-8859-1"));
// ps.flush();
System.out.println("send over!");
}
ps.flush();
}
} catch (IOException e) {
System.out.println("Client Connected Failed :\t");
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Thread Error!");
e.printStackTrace();
}finally{
closeConnection(s,in,out);
}
}
}
最近在写一个telnet客户端的代码,要求使用socket进行通讯而不是apache的工具包。遂本人在网上找了很多文档,结果发现和之前写的socket实时通讯的工具很像。于是我就毫不思索的将代码copy了一遍,结果运行时悲剧了。每次的socket连接自然没有问题,但是就是没有回应,我这边发送了数据,也没响应。
于是就郁闷了,本人是使用windows环境,telnet虚拟机的open solaris,可是不管怎么调试和修改,就是接受不到数据。没办法只能卡住了,把telnet协议和socket通讯又是一遍一遍的看,网上狂找文档,终于明白了问题的关键。socket通讯可以实现客户端和服务器进行通讯和数据传输,比如ftp,smtp等都可以,但是对于telnet而言,telnet时远程登陆的工具,它是跨平台的(WINDOWSH、LINUX等),因此在通讯时需要将数据和命令转换成双方约定好的格式(NVT,关于NVT这里不多讲,有个故事很形象的描述了这个问题)。
其实最重要的是了解telnet登陆时的细节,telnet在连接时,需要客户端和服务器进行协商,也就是双方规定发送数据的”标准“。