Java之~tenlet~篇(使用日本:小高知宏 著的 《TCP/IP Java篇》中的代码)~~外加本人讲解
1
/**/
/*
2 小高知宏 写的书叫《TCP/IP java篇》但我看起来,还想大都是应用层上的东西
3 好象应该叫《TCP/IP 应用层 java篇》 有点搞不清他的书名是从何而来的,呵呵!
4 这是小高知宏的Telnet的客户端程序,接下来我们看看它是怎么实现的
5 */
6
7 import java.net. * ;
8 import java.io. * ;
9
10 public class Telnet {
11 Socket serverSocket; // 创建服务器端SOCKET
12 public OutputStream serverOutput;
13 public BufferedInputStream serverInput;
14 String host; // 要连接的telnet服务器的地址或域名
15 int port; // 要连接的服务器端口
16
17 static final int DEFAULT_TELNET_PORT = 23 ; // 定义默认的Telnet端口
18
19 // 构造telnet的连接参数(含端口,就是当你使用23以外的端口时,调用这个函数体),有点像C的数据结构
20 public Telnet(String host, int port) {
21 this .host = host; // 这里不解释了THIS的用法前面讲过
22 this .port = port;
23 }
24 // 定义默认端口23对应的函数体
25 public Telnet(String host) {
26 this (host, DEFAULT_TELNET_PORT);
27
28 // 建立连接,将在客户端输入的数据host+port转换成数据流
29 public void openConnection()
30 throws IOException,UnknownHostException
31 {
32 serverSocket = new Socket(host, port); // 创建Socket
33 serverOutput = serverSocket.getOutputStream(); // 获取输入数据
34 serverInput = new BufferedInputStream(serverSocket.getInputStream()); // 装换数据
35 if (port == DEFAULT_TELNET_PORT) { // 判断端口是不是23
36 negotiation(serverInput, serverOutput); // 对输出和输入的数据进行分析,实现C/S端口的协商
37 }
38 }
39
40 public void main_proc() // 连接成功,启动网络线程
41 throws IOException
42 {
43 try {
44
45 // 生成线程的StreamConnector类的对象stdin_to_socket和socket_to_stdout
46 // 从这里看出java是如何用类去创建对象的
47 StreamConnector stdin_to_socket =
48 new StreamConnector(System.in, serverOutput); // StreamConnector这个类在后面有定义
49 StreamConnector socket_to_stdout =
50 new StreamConnector(serverInput, System.out);
51
52 // 生成对象对应的stdin_to_socket和socket_to_stdout线程事件input_thread和output_thread
53 // 看到java的事件是如何从对象中产生的
54 Thread input_thread = new Thread(stdin_to_socket);
55 Thread output_thread = new Thread(socket_to_stdout);
56
57 // 看看java如何启动或调用事件
58 input_thread.start();
59 output_thread.start();
60 }
61 // 整个过程可能会产生异常,这里进行捕获
62 catch (Exception e) {
63 System.err.print(e);
64 System.exit( 1 );
65 }
66 }
67 // 定义用于协商的命令
68 // 如果一个数据既是static又是final,那么他会拥有一块无法改变的存储空间
69 static final byte IAC = ( byte ) 255 ;
70 static final byte DONT = ( byte ) 254 ;
71 static final byte DO = ( byte ) 253 ;
72 static final byte WONT = ( byte ) 252 ;
73 static final byte WILL = ( byte ) 251 ;
74
75 // 利用NVT进行通信
76 /**/ /*
77 NVT是一种抽象的设备,由打印机和键盘组成。用户使用键盘键入的字符被转发到服务器中,
78 服务器再把数据返回给用户,而NVT在打印机上将其输出。它使用标准的回车与换行组合去
79 终止行。NVT提供控制操作,这些操作支持过程中断并丢弃多余的输出。这些操作是通过使
80 用IAC(Interpret as Command,解释成命令)代码发出的。IAC是一个单字节,由值255或十
81 六进制0xff组成。IAC后面可以跟着一个单字节,用于发送控制代码;或者后面跟着两个或
82 更多的字节,用于协商一选项。而为了发送已用于IAC的字节值255,可以通过一个特殊的字
83 节序列来实现:连续发送两个IAC。
84 JAVA实现应用层的不少东西都是用他实现的 如:HTTP
85 */
86
87 static void negotiation(
88 BufferedInputStream in,OutputStream out)
89 throws IOException
90 {
91 byte [] buff = new byte [ 3 ]; // 接收数据
92 while ( true ) {
93 in.mark(buff.length); // 在此缓冲区的位置设置其标记
94 if (in.available() >= buff.length) {
95 in.read(buff); // 读取缓冲区内容
96 if (buff[ 0 ] != IAC) { // 协商结束
97 in.reset(); // 将此缓冲区的位置重新设置成以前标记的位置
98 return ;
99 } else if (buff[ 1 ] == DO) { // 用于对DO的回应
100 buff[ 1 ] = WONT;
101 out.write(buff);
102 }
103 }
104 }
105 }
106
107 // 这里是主函数
108 public static void main(String[] arg) {
109 try {
110 Telnet t = null ; // 创建Telnet变量
111 switch (arg.length) {
112 case 1 : // 服务器名
113 t = new Telnet(arg[ 0 ]);
114 break ;
115 case 2 : // 服务器名+端口
116 t = new Telnet(arg[ 0 ], Integer.parseInt(arg[ 1 ]));
117 break ;
118 default : // 如果输入格式不对
119 System.out.println(
120 " usage: java Telnet <host name> {<port number>} " );
121 return ;
122 }
123 t.openConnection(); // 连接
124 t.main_proc(); // 创建线程
125 } catch (Exception e) {
126 e.printStackTrace();
127 System.exit( 1 );
128 }
129 }
130 }
131
132 // 定义StreamConnector类
133 // 定义前面的对象、事件的具体实现
134 class StreamConnector implements Runnable {
135 InputStream src = null ;
136 OutputStream dist = null ;
137
138 // 接收参数
139 public StreamConnector(InputStream in, OutputStream out) {
140 src = in;
141 dist = out;
142 }
143 // 用循环实现对数据流的读写
144 public void run() {
145 byte [] buff = new byte [ 1024 ]; // 一次处理的最大数据量
146 while ( true ) {
147 try {
148 int n = src.read(buff);
149 if (n > 0 )
150 dist.write(buff, 0 , n);
151 }
152 catch (Exception e) {
153 e.printStackTrace();
154 System.err.print(e);
155 System.exit( 1 );
156 }
157 }
158 }
159 }
160
2 小高知宏 写的书叫《TCP/IP java篇》但我看起来,还想大都是应用层上的东西
3 好象应该叫《TCP/IP 应用层 java篇》 有点搞不清他的书名是从何而来的,呵呵!
4 这是小高知宏的Telnet的客户端程序,接下来我们看看它是怎么实现的
5 */
6
7 import java.net. * ;
8 import java.io. * ;
9
10 public class Telnet {
11 Socket serverSocket; // 创建服务器端SOCKET
12 public OutputStream serverOutput;
13 public BufferedInputStream serverInput;
14 String host; // 要连接的telnet服务器的地址或域名
15 int port; // 要连接的服务器端口
16
17 static final int DEFAULT_TELNET_PORT = 23 ; // 定义默认的Telnet端口
18
19 // 构造telnet的连接参数(含端口,就是当你使用23以外的端口时,调用这个函数体),有点像C的数据结构
20 public Telnet(String host, int port) {
21 this .host = host; // 这里不解释了THIS的用法前面讲过
22 this .port = port;
23 }
24 // 定义默认端口23对应的函数体
25 public Telnet(String host) {
26 this (host, DEFAULT_TELNET_PORT);
27
28 // 建立连接,将在客户端输入的数据host+port转换成数据流
29 public void openConnection()
30 throws IOException,UnknownHostException
31 {
32 serverSocket = new Socket(host, port); // 创建Socket
33 serverOutput = serverSocket.getOutputStream(); // 获取输入数据
34 serverInput = new BufferedInputStream(serverSocket.getInputStream()); // 装换数据
35 if (port == DEFAULT_TELNET_PORT) { // 判断端口是不是23
36 negotiation(serverInput, serverOutput); // 对输出和输入的数据进行分析,实现C/S端口的协商
37 }
38 }
39
40 public void main_proc() // 连接成功,启动网络线程
41 throws IOException
42 {
43 try {
44
45 // 生成线程的StreamConnector类的对象stdin_to_socket和socket_to_stdout
46 // 从这里看出java是如何用类去创建对象的
47 StreamConnector stdin_to_socket =
48 new StreamConnector(System.in, serverOutput); // StreamConnector这个类在后面有定义
49 StreamConnector socket_to_stdout =
50 new StreamConnector(serverInput, System.out);
51
52 // 生成对象对应的stdin_to_socket和socket_to_stdout线程事件input_thread和output_thread
53 // 看到java的事件是如何从对象中产生的
54 Thread input_thread = new Thread(stdin_to_socket);
55 Thread output_thread = new Thread(socket_to_stdout);
56
57 // 看看java如何启动或调用事件
58 input_thread.start();
59 output_thread.start();
60 }
61 // 整个过程可能会产生异常,这里进行捕获
62 catch (Exception e) {
63 System.err.print(e);
64 System.exit( 1 );
65 }
66 }
67 // 定义用于协商的命令
68 // 如果一个数据既是static又是final,那么他会拥有一块无法改变的存储空间
69 static final byte IAC = ( byte ) 255 ;
70 static final byte DONT = ( byte ) 254 ;
71 static final byte DO = ( byte ) 253 ;
72 static final byte WONT = ( byte ) 252 ;
73 static final byte WILL = ( byte ) 251 ;
74
75 // 利用NVT进行通信
76 /**/ /*
77 NVT是一种抽象的设备,由打印机和键盘组成。用户使用键盘键入的字符被转发到服务器中,
78 服务器再把数据返回给用户,而NVT在打印机上将其输出。它使用标准的回车与换行组合去
79 终止行。NVT提供控制操作,这些操作支持过程中断并丢弃多余的输出。这些操作是通过使
80 用IAC(Interpret as Command,解释成命令)代码发出的。IAC是一个单字节,由值255或十
81 六进制0xff组成。IAC后面可以跟着一个单字节,用于发送控制代码;或者后面跟着两个或
82 更多的字节,用于协商一选项。而为了发送已用于IAC的字节值255,可以通过一个特殊的字
83 节序列来实现:连续发送两个IAC。
84 JAVA实现应用层的不少东西都是用他实现的 如:HTTP
85 */
86
87 static void negotiation(
88 BufferedInputStream in,OutputStream out)
89 throws IOException
90 {
91 byte [] buff = new byte [ 3 ]; // 接收数据
92 while ( true ) {
93 in.mark(buff.length); // 在此缓冲区的位置设置其标记
94 if (in.available() >= buff.length) {
95 in.read(buff); // 读取缓冲区内容
96 if (buff[ 0 ] != IAC) { // 协商结束
97 in.reset(); // 将此缓冲区的位置重新设置成以前标记的位置
98 return ;
99 } else if (buff[ 1 ] == DO) { // 用于对DO的回应
100 buff[ 1 ] = WONT;
101 out.write(buff);
102 }
103 }
104 }
105 }
106
107 // 这里是主函数
108 public static void main(String[] arg) {
109 try {
110 Telnet t = null ; // 创建Telnet变量
111 switch (arg.length) {
112 case 1 : // 服务器名
113 t = new Telnet(arg[ 0 ]);
114 break ;
115 case 2 : // 服务器名+端口
116 t = new Telnet(arg[ 0 ], Integer.parseInt(arg[ 1 ]));
117 break ;
118 default : // 如果输入格式不对
119 System.out.println(
120 " usage: java Telnet <host name> {<port number>} " );
121 return ;
122 }
123 t.openConnection(); // 连接
124 t.main_proc(); // 创建线程
125 } catch (Exception e) {
126 e.printStackTrace();
127 System.exit( 1 );
128 }
129 }
130 }
131
132 // 定义StreamConnector类
133 // 定义前面的对象、事件的具体实现
134 class StreamConnector implements Runnable {
135 InputStream src = null ;
136 OutputStream dist = null ;
137
138 // 接收参数
139 public StreamConnector(InputStream in, OutputStream out) {
140 src = in;
141 dist = out;
142 }
143 // 用循环实现对数据流的读写
144 public void run() {
145 byte [] buff = new byte [ 1024 ]; // 一次处理的最大数据量
146 while ( true ) {
147 try {
148 int n = src.read(buff);
149 if (n > 0 )
150 dist.write(buff, 0 , n);
151 }
152 catch (Exception e) {
153 e.printStackTrace();
154 System.err.print(e);
155 System.exit( 1 );
156 }
157 }
158 }
159 }
160
地震让大伙知道:居安思危,才是生存之道。