一.網絡通信,常見的結構是C/S模式。客戶端在需要服務時向服務器請求連接,服務端被動接收連接,建立連接后,雙方開始通信。服務器進程一般作為守護進程,一直運行,不斷監聽網絡端口,被動接收客戶端的請求,當接收到客戶的請求時,會啟動一個服務進程來處理客戶的請求,并繼續監聽網絡端口。
(上圖轉自:http://tutorials.jenkov.com/java-networking/index.html)
二.網絡上進程之間通過雙向的通信連接來實現信息的交換。這樣連接的一端稱為一個Socket。Socket由ip號和端口號確定。在java中使用Socket來實現基于TCP/IP協議的網絡程序,主要涉及到下面幾步:
客戶端:
1.根據服務器的IP和端口號,建立Socket
2.打開輸入、輸出流
3.對Socket進行讀寫
4.關閉輸入、輸出流,關閉套接字
服務器端:
1.根據端口號建立ServerSocket
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.); //每個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;//Serverpublic 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這一塊,好多不清楚。麻煩看到的童鞋幫解答下。。。
新聞熱點
疑難解答