?
??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

??3

??4

??5

??6

??7

??8

??9

?10



?11

?12

?13

?14

?15

?16

?17

?18

?19

?20



?21

?22

?23

?24

?25



?26

?27

?28

?29

?30

?31



?32

?33

?34

?35



?36

?37

?38

?39

?40

?41

?42



?43



?44

?45

?46

?47

?48

?49

?50

?51

?52

?53

?54

?55

?56

?57

?58

?59

?60

?61

?62



?63

?64

?65

?66

?67

?68

?69

?70

?71

?72

?73

?74

?75

?76


?77

?78

?79

?80

?81

?82

?83

?84

?85

?86

?87

?88

?89

?90



?91

?92



?93

?94



?95

?96



?97

?98

?99



100

101

102

103

104

105

106

107

108



109



110

111



112

113

114

115

116

117

118

119

120

121

122

123

124

125



126

127

128

129

130

131

132

133

134



135

136

137

138

139



140

141

142

143

144



145

146



147



148

149

150

151

152



153

154

155

156

157

158

159

160

地震讓大伙知道:居安思危,才是生存之道。
