轉自:http://www.importnew.com/19635.html
TCP的Java支持
協議相當於相互通信的程序間達成的一種約定,它規定了分組報文的結構、交換方式、包含的意義以及怎樣對報文所包含的信息進行解析,TCP/IP協議族有IP協議、TCP協議和UDP協議。現在TCP/IP協議族中的主要socket類型為流套接字(使用TCP協議)和數據報套接字(使用UDP協議)。
TCP協議提供面向連接的服務,通過它建立的是可靠地連接。Java為TCP協議提供了兩個類:Socket類和ServerSocket類。一個Socket實例代表了TCP連接的一個客戶端,而一個ServerSocket實例代表了TCP連接的一個服務器端,一般在TCP Socket編程中,客戶端有多個,而服務器端只有一個,客戶端TCP向服務器端TCP發送連接請求,服務器端的ServerSocket實例則監聽來自客戶端的TCP連接請求,並為每個請求創建新的Socket實例,由於服務端在調用accept()等待客戶端的連接請求時會阻塞,直到收到客戶端發送的連接請求才會繼續往下執行代碼,因此要為每個Socket連接開啟一個線程。服務器端要同時處理ServerSocket實例和Socket實例,而客戶端只需要使用Socket實例。另外,每個Socket實例會關聯一個InputStream和OutputStream對象,我們通過將字節寫入套接字的OutputStream來發送數據,並通過從InputStream來接收數據。
TCP連接的建立步驟
客戶端向服務器端發送連接請求后,就被動地等待服務器的響應。典型的TCP客戶端要經過下面三步操作:
1、創建一個Socket實例:構造函數向指定的遠程主機和端口建立一個TCP連接;
2.通過套接字的I/O流與服務端通信;
3、使用Socket類的close方法關閉連接。
服務端的工作是建立一個通信終端,並被動地等待客戶端的連接。典型的TCP服務端執行如下兩步操作:
1、創建一個ServerSocket實例並指定本地端口,用來監聽客戶端在該端口發送的TCP連接請求;
2、重復執行:
1)調用ServerSocket的accept()方法以獲取客戶端連接,並通過其返回值創建一個Socket實例;
2)為返回的Socket實例開啟新的線程,並使用返回的Socket實例的I/O流與客戶端通信;
3)通信完成后,使用Socket類的close()方法關閉該客戶端的套接字連接。
TCP Socket Demo
下面給出一個客戶端服務端TCP通信的Demo,該客戶端在20006端口請求與服務端建立TCP連接,客戶端不斷接收鍵盤輸入,並將其發送到服務端,服務端在接收到的數據前面加上“echo”字符串,並將組合后的字符串發回給客戶端,如此循環,直到客戶端接收到鍵盤輸入“bye”為止。
客戶端代碼如下:
1
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
|
package
zyb.org.client;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.PrintStream;
import
java.net.Socket;
import
java.net.SocketTimeoutException;
public
class
Client1 {
public
static
void
main(String[] args)
throws
IOException {
//客戶端請求與本機在20006端口建立TCP連接
Socket client =
new
Socket(
"127.0.0.1"
,
20006
);
client.setSoTimeout(
10000
);
//獲取鍵盤輸入
BufferedReader input =
new
BufferedReader(
new
InputStreamReader(System.in));
//獲取Socket的輸出流,用來發送數據到服務端
PrintStream out =
new
PrintStream(client.getOutputStream());
//獲取Socket的輸入流,用來接收從服務端發送過來的數據
BufferedReader buf =
new
BufferedReader(
new
InputStreamReader(client.getInputStream()));
boolean
flag =
true
;
while
(flag){
System.out.print(
"輸入信息:"
);
String str = input.readLine();
//發送數據到服務端
out.println(str);
if
(
"bye"
.equals(str)){
flag =
false
;
}
else
{
try
{
//從服務器端接收數據有個時間限制(系統自設,也可以自己設置),超過了這個時間,便會拋出該異常
String echo = buf.readLine();
System.out.println(echo);
}
catch
(SocketTimeoutException e){
System.out.println(
"Time out, No response"
);
}
}
}
input.close();
if
(client !=
null
){
//如果構造函數建立起了連接,則關閉套接字,如果沒有建立起連接,自然不用關閉
client.close();
//只關閉socket,其關聯的輸入輸出流也會被關閉
}
}
}
|
服務端需要用到多線程,這里單獨寫了一個多線程類,代碼如下:
1
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
|
package
zyb.org.server;
import
java.io.BufferedReader;
import
java.io.InputStreamReader;
import
java.io.PrintStream;
import
java.net.Socket;
/**
* 該類為多線程類,用於服務端
*/
public
class
ServerThread
implements
Runnable {
private
Socket client =
null
;
public
ServerThread(Socket client){
this
.client = client;
}
@Override
public
void
run() {
try
{
//獲取Socket的輸出流,用來向客戶端發送數據
PrintStream out =
new
PrintStream(client.getOutputStream());
//獲取Socket的輸入流,用來接收從客戶端發送過來的數據
BufferedReader buf =
new
BufferedReader(
new
InputStreamReader(client.getInputStream()));
boolean
flag =
true
;
while
(flag){
//接收從客戶端發送過來的數據
String str = buf.readLine();
if
(str ==
null
||
""
.equals(str)){
flag =
false
;
}
else
{
if
(
"bye"
.equals(str)){
flag =
false
;
}
else
{
//將接收到的字符串前面加上echo,發送到對應的客戶端
out.println(
"echo:"
+ str);
}
}
}
out.close();
client.close();
}
catch
(Exception e){
e.printStackTrace();
}
}
}
|
服務端處理TCP連接請求的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
zyb.org.server;
import
java.net.ServerSocket;
import
java.net.Socket;
public
class
Server1 {
public
static
void
main(String[] args)
throws
Exception{
//服務端在20006端口監聽客戶端請求的TCP連接
ServerSocket server =
new
ServerSocket(
20006
);
Socket client =
null
;
boolean
f =
true
;
while
(f){
//等待客戶端的連接,如果沒有獲取連接
client = server.accept();
System.out.println(
"與客戶端連接成功!"
);
//為每個客戶端連接開啟一個線程
new
Thread(
new
ServerThread(client)).start();
}
server.close();
}
}
|