Java中網絡編程之TCP協議
一、TCP的基本概念
TCP是專門設計用於在不可靠的英特網上提供可靠的、端到端的字節流通信的協議,是一個麵向連接的協議,TCP連接是字節流而非報文流。UDP和TCP各有65536個端口號互不影響。
二、單線程服務端
以下代碼隻能實現服務端和客戶端的同步對話。服務端處理完一個客戶端請求,才會處理另一個客戶端請求。服務器端的輸出效果是Client1阻塞20秒,Client2不會執行。必須等Client1阻塞結束之後,Client2才會執行。該例子可用來學習TCP的基本語法。
/** * TCP客戶端1 * * @author 徐越 * */ public class Client1 { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 8821); OutputStream os = socket.getOutputStream(); String msg = "我是徐越1"; Thread.sleep(20000); os.write(msg.getBytes()); os.flush(); os.close();socket.close(); } } /** * TCP客戶端2 * * @author 徐越 * */ public class Client2 { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 8821); OutputStream os = socket.getOutputStream(); String msg = "我是徐越2"; os.write(msg.getBytes()); os.flush(); os.close();socket.close(); } } /** * 單線程TCP服務端 * * @author 徐越 * */ public class Server { public static void main(String[] args) throws Exception { // 創建端口為8821的TCP服務器端對象 // 8821是服務器端的端口號而客戶端從某端口A連到8821,端口A是隨機的 ServerSocket serverSocket = new ServerSocket(8821); while (true) { // 若無客戶端發送請求則線程在此阻塞,方法不繼續執行 Socket socket = serverSocket.accept(); System.out.println("connected"); InputStream instream = socket.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len = instream.read(buffer)) != -1) { bos.write(buffer, 0, len); } instream.close(); bos.flush(); bos.close(); String msg = bos.toString(); System.out.println("客戶端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客戶端的端口:" + socket.getPort()); System.out.println("客戶端的信息:" + msg); } } }
執行結果
connected
客戶端的IP:127.0.0.1
客戶端的端口:3775
客戶端的信息:我是徐越1
connected
客戶端的IP:127.0.0.1
客戶端的端口:3787
客戶端的信息:我是徐越2
三、多線程服務器
在實際應用中是在服務器上運行一個永久的程序,接收來自其他多個客戶端的請求,提供相應的服務。需要利用多線程實現多客戶機製。服務器在指定的端口上監聽是否有客戶請求,一旦監聽到就會啟動一個專門的服務線程來響應該請求,而服務器本身在啟動完線程之後馬上又進入監聽狀態,等待下一個客戶的到來。隻要將服務端為如下代碼,Client1和Client2就會異步執行。
/** * 多線程服務端0 * * @author 徐越 * */ public class MultiThreadServer0 { // 端口號 private int port = 8821; // 服務端 private ServerSocket serverSocket; public MultiThreadServer0() throws IOException { // 創建服務器端 serverSocket = new ServerSocket(port); System.out.println("服務器啟動"); } public void service() { while (true) { Socket socket = null; try { // 客戶端進行連接時會觸發accept方法從而建立連接 socket = serverSocket.accept(); new MultiThreadHandler(socket).start(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new MultiThreadServer1().service(); } } /** * 多線程處理類 */ class MultiThreadHandler extends Thread { private Socket socket; public MultiThreadHandler(Socket socket) { this.socket = socket; } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); // InputStreamReader為轉換流 // InputStream本是字節流,現加一個Reader,表示用字符流的方式讀取字節流 InputStreamReader isr = new InputStreamReader(socketIn); return new BufferedReader(isr); } public void run() { try { BufferedReader br = getReader(socket); String msg = null; while ((msg = br.readLine()) != null) { System.out.println("客戶端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客戶端的端口:" + socket.getPort()); System.out.println("客戶端的信息:" + msg); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } } /** * 多線程服務端1 */ public class MultiThreadServer1 { // 端口號 private int port = 8821; // 服務端 private ServerSocket serverSocket; // 線程池 private ExecutorService executorService; // 單個CPU線程池大小 private final int POOL_SIZE = 10; public MultiThreadServer1() throws IOException { // 創建服務器端 serverSocket = new ServerSocket(port); // 獲取當前係統的CPU數目 int cpuNums = Runtime.getRuntime().availableProcessors(); // 根據係統資源情況靈活定義線程池大小 executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE); System.out.println("服務器啟動"); } public void service() { while (true) { Socket socket = null; try { // 客戶進行連接就會觸發accept方法從而建立連接 socket = serverSocket.accept(); // 調用線程池操作 executorService.execute(new Handler(socket)); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new MultiThreadServer1().service(); } } /** * 多線程處理類 */ class Handler implements Runnable { private Socket socket; public Handler(Socket socket) { this.socket = socket; } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); // InputStreamReader為轉換流 // InputStream本是字節流,現加一個Reader,表示用字符流的方式讀取字節流 InputStreamReader isr = new InputStreamReader(socketIn); return new BufferedReader(isr); } public void run() { try { BufferedReader br = getReader(socket); String msg = null; while ((msg = br.readLine()) != null) { System.out.println("客戶端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客戶端的端口:" + socket.getPort()); System.out.println("客戶端的信息:" + msg); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
兩個多線程服務端執行結果相同
服務器啟動
客戶端的IP:127.0.0.1
客戶端的端口:3931
客戶端的信息:我是徐越2
客戶端的IP:127.0.0.1
客戶端的端口:3928
客戶端的信息:我是徐越1
參考地址:https://www.2cto.com/kf/201209/158518.html
最後更新:2017-04-04 07:03:12