【Java TCP/IP Socket】TCP Socket(含代碼)


轉自: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();
     }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM