一.網絡通訊,常見的結構是C/S模式。客戶端在須要服務時向服務器請求鏈接,服務端被動接收鏈接,創建鏈接後,雙方開始通訊。服務器進程通常做爲守護進程,一直運行,不斷監聽網絡端口,被動接收客戶端的請求,當接收到客戶的請求時,會啓動一個服務進程來處理客戶的請求,並繼續監聽網絡端口。html
(上圖轉自:http://tutorials.jenkov.com/java-networking/index.html)java
二.網絡上進程之間經過雙向的通訊鏈接來實現信息的交換。這樣鏈接的一端稱爲一個Socket。Socket由IP號和端口號肯定。在java中使用Socket來實現基於TCP/IP協議的網絡程序,主要涉及到下面幾步:服務器
客戶端:網絡
1.根據服務器的IP和端口號,創建Socketsocket
2.打開輸入、輸出流this
3.對Socket進行讀寫spa
4.關閉輸入、輸出流,關閉套接字.net
服務器端:線程
1.根據端口號創建ServerSocketcode
2.被動監聽客戶端請求
3.當監聽到客戶端請求時,接收請求,啓動工做線程,處理請求。若再也不接收請求時,進入4;不然,繼續監聽,轉2
4.關閉ServerSocket
下面以例子來講明:
客戶端代碼:
package com.net.examples; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { /** * @param args * @throws IOException * @throws UnknownHostException * @throws InterruptedException */ public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { //這裏假設有三個client,每一個client分別發送一次請求 int clientCount = 3; MyRunable run = new MyRunable(); while(clientCount > 0){ //每一個線程模擬一個client,三個線程名分別爲1,2,3 new Thread(run,clientCount+"").start(); clientCount--; } } } //定義MyRunable,重寫run方法實現client線程 class MyRunable implements Runnable{ public void run() { int messCount = 2; Socket socket = null; DataOutputStream o = null; DataInputStream in = null; try { //1.建立Socket,創建鏈接 socket = new Socket("127.0.0.1",8080); //2.打開輸入輸出流 o = new DataOutputStream(socket.getOutputStream()); in = new DataInputStream(socket.getInputStream()); System.out.println("Clients begin send messages"); //每一個client對Socket寫兩次 while(messCount > 0 ){ try { //3.對Socket進行寫 o.writeUTF("" + messCount); o.flush(); } catch (IOException e) { e.printStackTrace(); } System.out.println("I am client:"+Thread.currentThread().getName() +",I send message:" + messCount); messCount--; } //對Socket進行讀 System.out.println("I am client:" + Thread.currentThread().getName() + ",and server "+ in.readUTF() + "(me!)"); } catch (IOException e2) { e2.printStackTrace(); } finally{ try { //4.關閉輸入輸出流,關閉socket,釋放資源 o.close(); in.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
服務端代碼:
package com.net.examples; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; //Server public class Server { private static int clientCount = 3; //Server線程結束運行條件,這裏是假設知道一共會收到三次客戶端請求 private static boolean isStop(){ return clientCount == 0 ? true:false; } public static void main(String[] args) throws IOException, InterruptedException { //1.創建ServerSocket ServerSocket serverSocket = new ServerSocket(8080); //2.監聽客戶端請求 while(!isStop()){ //3.接收到客戶端請求,並啓動一個線程處理 Socket client = serverSocket.accept(); new MyThread(client,clientCount).start(); clientCount--; } //4.關閉ServerSocket serverSocket.close(); } } //客戶端請求處理線程 class MyThread extends Thread{ private Socket clientSocket; private int id; private DataInputStream input; private DataOutputStream output ; public MyThread (){ } public MyThread(Socket soc,int i){ this.clientSocket = soc; this.id = i; } public void run(){ try { //得到輸入輸出流 input = new DataInputStream((clientSocket.getInputStream())); output = new DataOutputStream(clientSocket.getOutputStream()); int count = 2; //讀取Socket while(count > 0){ System.out.println("I am server.I have received message:" + input.readUTF() + ",from" + id); count --; } //寫Socket output.writeUTF("respose to client" + id); output.flush();; } catch (IOException e) { e.printStackTrace(); }finally { try { //釋放資源,關閉鏈接 input.close(); output.close(); clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
運行結果以下:
client:
Server:
不過,後來我稍微地改了下Client.java文件中MyRunable.java,輸出流o,在對Socket寫完以後,就調用了o.close()方法,而不是在讀完Socket後釋放掉,從新跑程序後client跑的就有錯出現了,Server程序沒出錯。具體如改動下紅色的部分,而報錯也以下圖:
個人理解是,輸出流不用了,因此就close()了,爲何在讀Socket時(58行的代碼),會報socket closed這樣的出錯信息。難道調用o.close()時,會關閉socket??或者是其餘緣由,實在不理解,剛剛看着java Socket這一塊,好多不清楚。麻煩看到的童鞋幫解答下。。。