【Java TCP/IP Socket】TCP Socket(含代碼)
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”為止。
客戶端代碼如下:
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,其關聯的輸入輸出流也會被關閉 } } }
服務端需要用到多線程,這裏單獨寫了一個多線程類,代碼如下:
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連接請求的代碼如下:
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(); } }
執行結果截圖如下:
轉自:http://blog.csdn.net/ns_code/article/details/14105457
【Java TCP/IP Socket】TCP Socket(含代碼)