?
??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
地震讓大伙知道:居安思危,才是生存之道。
posted on 2007-03-09 00:14
小尋 閱讀(863)
評論(0) 編輯 收藏 所屬分類:
j2se/j2ee/j2me