Java.io 包幾乎包含了全部操做輸入、輸出須要的類。全部這些流類表明了輸入源和輸出目標。html
Java.io 包中的流支持不少種格式,好比:基本類型、對象、本地化字符集等等。java
一個流能夠理解爲一個數據的序列。輸入流表示從一個源讀取數據,輸出流表示向一個目標寫數據。mysql
Java 爲 I/O 提供了強大的而靈活的支持,使其更普遍地應用到文件傳輸和網絡編程中。程序員
Java 的控制檯輸入由 System.in 完成。sql
爲了得到一個綁定到控制檯的字符流,你能夠把 System.in 包裝在一個 BufferedReader 對象中來建立一個字符流。數據庫
下面是建立 BufferedReader 的基本語法:編程
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader 對象建立後,咱們即可以使用 read() 方法從控制檯讀取一個字符,或者用 readLine() 方法讀取一個字符串。windows
從 BufferedReader 對象讀取一個字符要使用 read() 方法,每次調用 read() 方法,它從輸入流讀取一個字符並把該字符做爲整數值返回。 當流結束的時候返回 -1。該方法拋出 IOException。數組
// 使用 BufferedReader 在控制檯讀取字符 package four; import java.io.*; public class BRRead { public static void main(String args[]) throws IOException { char c; // 使用 System.in 建立 BufferedReader BufferedReader br = new BufferedReader( new InputStreamReader(System.in) ); System.out.println("輸入字符, 按下 'q' 鍵退出。"); // 讀取字符 do { c = (char) br.read(); System.out.println(c); } while(c != 'q'); } } /*輸出結果 輸入字符, 按下 'q' 鍵退出。 suoning s u o n i n g q q */
從標準輸入讀取一個字符串須要使用 BufferedReader 的 readLine() 方法。緩存
它的通常格式是:
String readLine( ) throws IOException
// 使用 BufferedReader 在控制檯讀取字符 package four; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class BRReadLines { public static void main(String args[]) throws IOException { // 使用 System.in 建立 BufferedReader BufferedReader br = new BufferedReader(new InputStreamReader(System.in) ); String str; System.out.println("Enter lines of text."); System.out.println("Enter 'end' to quit."); do { str = br.readLine(); System.out.println(str); } while(!str.equals("end")); } } /*輸出結果 Enter lines of text. Enter 'end' to quit. suoning suoning end end */
控制檯的輸出由 print( ) 和 println() 完成。這些方法都由類 PrintStream 定義,System.out 是該類對象的一個引用。
PrintStream 繼承了 OutputStream類,而且實現了方法 write()。這樣,write() 也能夠用來往控制檯寫操做。
PrintStream 定義 write() 的最簡單格式以下所示:
void write(int byteval)
// 演示 System.out.write(). import java.io.*; public class WriteDemo { public static void main(String args[]) { int b; b = 'S'; System.out.write(b); System.out.write('\n'); } } /*輸出結果 S */
java.util.Scanner 是 Java5 的新特徵,咱們能夠經過 Scanner 類來獲取用戶的輸入。
下面是建立 Scanner 對象的基本語法:
Scanner s = new Scanner(System.in);
package four; import java.util.Scanner; public class ScannerDemo { public static void main(String[] args) { Scanner scan = new Scanner(System.in); // 從鍵盤接收數據 //next方式接收字符串 System.out.println("next方式接收:"); // 判斷是否還有輸入 if(scan.hasNext()){ String str1 = scan.next(); System.out.println("輸入的數據爲:"+str1); } } } /*輸出結果 next方式接收: suo ning 輸入的數據爲:suo */
package four; import java.util.Scanner; public class ScannerLinesDemo { public static void main(String[] args) { Scanner scan = new Scanner(System.in); // 從鍵盤接收數據 //nextLine方式接收字符串 System.out.println("nextLine方式接收:"); // 判斷是否還有輸入 if(scan.hasNextLine()){ String str2 = scan.nextLine(); System.out.println("輸入的數據爲:"+str2); } } } /*輸出結果 nextLine方式接收: suo ning 輸入的數據爲:suo ning */
next():
nextLine():
輸入以前最好先使用 hasNextXxx() 方法進行驗證,再使用 nextXxx() 來讀取。
package four; import java.util.Scanner; public class ScannerHGDemo { public static void main(String[] args) { Scanner scan = new Scanner(System.in); // 從鍵盤接收數據 int i = 0 ; float f = 0.0f ; System.out.print("輸入整數:"); if(scan.hasNextInt()){ // 判斷輸入的是不是整數 i = scan.nextInt() ; // 接收整數 System.out.println("整數數據:" + i) ; }else{ // 輸入錯誤的信息 System.out.println("輸入的不是整數!") ; } System.out.print("輸入小數:"); if(scan.hasNextFloat()){ // 判斷輸入的是不是小數 f = scan.nextFloat() ; // 接收小數 System.out.println("小數數據:" + f) ; }else{ // 輸入錯誤的信息 System.out.println("輸入的不是小數!") ; } Scanner scan1 = new Scanner(System.in); System.out.print("輸入個數:"); double sum = 0; int m = 0; while(scan1.hasNextDouble()) { double x = scan1.nextDouble(); m = m + 1; sum = sum + x; } System.out.println(m+"個數的和爲"+sum); System.out.println(m+"個數的平均值是"+(sum/m)); } } /*輸出結果 輸入整數:1 整數數據:1 輸入小數:1.1 小數數據:1.1 輸入個數:10 1個數的和爲10.0 1個數的平均值是10.0 */
一個流被定義爲一個數據序列。輸入流用於從源讀取數據,輸出流用於向目標寫數據。
下圖是一個描述輸入流和輸出流的類層次圖。
該流用於從文件讀取數據,它的對象能夠用關鍵字 new 來建立。
有多種構造方法可用來建立對象。
InputStream f = new FileInputStream("C:/java/hello"); File f = new File("C:/java/hello"); InputStream f = new FileInputStream(f);
建立了InputStream對象,就可使用下面的方法來讀取流或者進行其餘的流操做:
序號 | 方法及描述 |
---|---|
1 | public void close() throws IOException{} 關閉此文件輸入流並釋放與此流有關的全部系統資源。拋出IOException異常。 |
2 | protected void finalize()throws IOException {} 這個方法清除與該文件的鏈接。確保在再也不引用文件輸入流時調用其 close 方法。拋出IOException異常。 |
3 | public int read(int r)throws IOException{} 這個方法從 InputStream 對象讀取指定字節的數據。返回爲整數值。返回下一字節數據,若是已經到結尾則返回-1。 |
4 | public int read(byte[] r) throws IOException{} 這個方法從輸入流讀取r.length長度的字節。返回讀取的字節數。若是是文件結尾則返回-1。 |
5 | public int available() throws IOException{} 返回下一次對此輸入流調用的方法能夠不受阻塞地今後輸入流讀取的字節數。返回一個整數值。 |
該類用來建立一個文件並向文件中寫數據。
若是該流在打開文件進行輸出前,目標文件不存在,那麼該流會建立該文件。
OutputStream f = new FileOutputStream("C:/java/hello") File f = new File("C:/java/hello"); OutputStream f = new FileOutputStream(f);
建立OutputStream 對象完成後,就可使用下面的方法來寫入流或者進行其餘的流操做:
序號 | 方法及描述 |
---|---|
1 | public void close() throws IOException{} 關閉此文件輸入流並釋放與此流有關的全部系統資源。拋出IOException異常。 |
2 | protected void finalize()throws IOException {} 這個方法清除與該文件的鏈接。確保在再也不引用文件輸入流時調用其 close 方法。拋出IOException異常。 |
3 | public void write(int w)throws IOException{} 這個方法把指定的字節寫到輸出流中。 |
4 | public void write(byte[] w) 把指定數組中w.length長度的字節寫到OutputStream中。 |
package four; import java.io.*; public class myFileInputStream { public static void main(String[] args){ try{ byte bWrite [] = {11,22,33,55,66}; OutputStream os = new FileOutputStream("F:\\sql_text\\department.txt"); for(int x=0;x<bWrite.length;x++){ os.write(bWrite[x]); } os.close(); InputStream is = new FileInputStream("F:\\sql_text\\department.txt"); int size = is.available(); for(int i=0;i<size;i++){ System.out.print(is.read()); } is.close(); } catch(IOException e){ System.out.println("IOException.."); } } }
上面的程序首先建立文件test.txt,並把給定的數字以二進制形式寫進該文件,同時輸出到控制檯上。
以上代碼因爲是二進制寫入,可能存在亂碼,你可使用如下代碼實例來解決亂碼問題:
package four; import java.io.*; public class fileStreamTest2{ public static void main(String[] args) throws IOException { File f = new File("F:\\sql_text\\department.txt"); FileOutputStream fop = new FileOutputStream(f); // 構建FileOutputStream對象,文件不存在會自動新建 OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8"); // 構建OutputStreamWriter對象,參數能夠指定編碼,默認爲操做系統默認編碼,windows上是gbk writer.append("中文輸入"); // 寫入到緩衝區 writer.append("\r\n"); //換行 writer.append("English"); // 刷新緩存衝,寫入到文件,若是下面已經沒有寫入的內容了,直接close也會寫入 writer.close(); //關閉寫入流,同時會把緩衝區內容寫入文件,因此上面的註釋掉 fop.close(); // 關閉輸出流,釋放系統資源 FileInputStream fip = new FileInputStream(f); // 構建FileInputStream對象 InputStreamReader reader = new InputStreamReader(fip, "UTF-8"); // 構建InputStreamReader對象,編碼與寫入相同 StringBuffer sb = new StringBuffer(); while (reader.ready()) { sb.append((char) reader.read()); // 轉成char加到StringBuffer對象中 } System.out.println(sb.toString()); reader.close(); // 關閉讀取流 fip.close(); // 關閉輸入流,釋放系統資源 } }
要理解Java異常處理是如何工做的,你須要掌握如下三種類型的異常:
全部的異常類是從 java.lang.Exception 類繼承的子類。
Exception 類是 Throwable 類的子類。除了Exception類外,Throwable還有一個子類Error 。
Java 程序一般不捕獲錯誤。錯誤通常發生在嚴重故障時,它們在Java程序處理的範疇以外。
Error 用來指示運行時環境發生的錯誤。
例如,JVM 內存溢出。通常地,程序不會從錯誤中恢復。
異常類有兩個主要的子類:IOException 類和 RuntimeException 類。
Java 語言定義了一些異常類在 java.lang 標準包中。
標準運行時異常類的子類是最多見的異常類。因爲 java.lang 包是默認加載到全部的 Java 程序的,因此大部分從運行時異常類繼承而來的異常均可以直接使用。
Java 根據各個類庫也定義了一些其餘的異常,下面的表中列出了 Java 的非檢查性異常。
異常 | 描述 |
---|---|
ArithmeticException | 當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。 |
ArrayIndexOutOfBoundsException | 用非法索引訪問數組時拋出的異常。若是索引爲負或大於等於數組大小,則該索引爲非法索引。 |
ArrayStoreException | 試圖將錯誤類型的對象存儲到一個對象數組時拋出的異常。 |
ClassCastException | 當試圖將對象強制轉換爲不是實例的子類時,拋出該異常。 |
IllegalArgumentException | 拋出的異常代表向方法傳遞了一個不合法或不正確的參數。 |
IllegalMonitorStateException | 拋出的異常代表某一線程已經試圖等待對象的監視器,或者試圖通知其餘正在等待對象的監視器而自己沒有指定監視器的線程。 |
IllegalStateException | 在非法或不適當的時間調用方法時產生的信號。換句話說,即 Java 環境或 Java 應用程序沒有處於請求操做所要求的適當狀態下。 |
IllegalThreadStateException | 線程沒有處於請求操做所要求的適當狀態時拋出的異常。 |
IndexOutOfBoundsException | 指示某排序索引(例如對數組、字符串或向量的排序)超出範圍時拋出。 |
NegativeArraySizeException | 若是應用程序試圖建立大小爲負的數組,則拋出該異常。 |
NullPointerException | 當應用程序試圖在須要對象的地方使用 null 時,拋出該異常 |
NumberFormatException | 當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換爲適當格式時,拋出該異常。 |
SecurityException | 由安全管理器拋出的異常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此異常由 String 方法拋出,指示索引或者爲負,或者超出字符串的大小。 |
UnsupportedOperationException | 當不支持請求的操做時,拋出該異常。 |
下面的表中列出了 Java 定義在 java.lang 包中的檢查性異常類。
異常 | 描述 |
---|---|
ClassNotFoundException | 應用程序試圖加載類時,找不到相應的類,拋出該異常。 |
CloneNotSupportedException | 當調用 Object 類中的 clone 方法克隆對象,但該對象的類沒法實現 Cloneable 接口時,拋出該異常。 |
IllegalAccessException | 拒絕訪問一個類的時候,拋出該異常。 |
InstantiationException | 當試圖使用 Class 類中的 newInstance 方法建立一個類的實例,而指定的類對象由於是一個接口或是一個抽象類而沒法實例化時,拋出該異常。 |
InterruptedException | 一個線程被另外一個線程中斷,拋出該異常。 |
NoSuchFieldException | 請求的變量不存在 |
NoSuchMethodException | 請求的方法不存在 |
下面的列表是 Throwable 類的主要方法:
序號 | 方法及說明 |
---|---|
1 | public String getMessage() 返回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了。 |
2 | public Throwable getCause() 返回一個Throwable 對象表明異常緣由。 |
3 | public String toString() 使用getMessage()的結果返回類的串級名字。 |
4 | public void printStackTrace() 打印toString()結果和棧層次到System.err,即錯誤輸出流。 |
5 | public StackTraceElement [] getStackTrace() 返回一個包含堆棧層次的數組。下標爲0的元素表明棧頂,最後一個元素表明方法調用堆棧的棧底。 |
6 | public Throwable fillInStackTrace() 用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。 |
使用 try 和 catch 關鍵字能夠捕獲異常。try/catch 代碼塊放在異常可能發生的地方。
try/catch代碼塊中的代碼稱爲保護代碼,使用 try/catch 的語法以下:
try { // 程序代碼 }catch(ExceptionName e1) { //Catch 塊 }
一個 try 代碼塊後面跟隨多個 catch 代碼塊的狀況就叫多重捕獲。
finally 關鍵字用來建立在 try 代碼塊後面執行的代碼塊。
不管是否發生異常,finally 代碼塊中的代碼總會被執行。
在 finally 代碼塊中,能夠運行清理類型等收尾善後性質的語句。
try{ // 程序代碼 }catch(異常類型1 異常的變量名1){ // 程序代碼 }catch(異常類型2 異常的變量名2){ // 程序代碼 }finally{ // 程序代碼 }
//ExcepTest.java package five; import java.*; public class ExcepTest { public static void main(String args[]){ try{ int a[] = new int[2]; System.out.printf("Access element three :%s", a[3]); } catch (ArrayIndexOutOfBoundsException e) { System.out.printf("Exception thrown : %s", e); } finally{ System.out.println("Finally."); } } } // Exception thrown : java.lang.ArrayIndexOutOfBoundsException: 3Finally.
若是一個方法沒有捕獲一個檢查性異常,那麼該方法必須使用 throws 關鍵字來聲明。throws 關鍵字放在方法簽名的尾部。
也可使用 throw 關鍵字拋出一個異常,不管它是新實例化的仍是剛捕獲到的。
//testthrow.java package five; import java.io.*; import java.rmi.RemoteException; import javax.naming.InsufficientResourcesException; public class testthrow { public void deposit (double amount) throws RemoteException { throw new RemoteException(); } public void withdraw (double amount) throws RemoteException, InsufficientResourcesException{ // 多個異常 } }
在 Java 中你能夠自定義異常。編寫本身的異常類時須要記住下面的幾點。
能夠像下面這樣定義本身的異常類:
class MyException extends Exception{ }
//MyException.java package five; public class MyException extends Exception { private double amont; public MyException(double amount){ this.amont = amount; } public double getAmount (){ return amont; } }
//CheckingAccount.java package five; public class CheckingAccount { public double balance; private int number; public CheckingAccount(int number){ this.number = number; } public void deposit(double amount){ balance += amount; } public void withdraw(double amount) throws MyException{ if (amount <= balance){ balance -= amount; } else { double needs = amount - balance; throw new MyException(needs); } } public double getBalance(){ return balance; } public int getNumber(){ return number; } }
package five; public class BankDemo { public static void main(String[] args){ CheckingAccount c = new CheckingAccount(99); c.deposit(66); try{ c.withdraw(10); System.out.println("10"); c.withdraw(88); } catch (MyException e) { System.out.println("error Myerror " + e); System.out.println("error Myerror " + e.getAmount()); e.printStackTrace(); } }; } /* * 10 error Myerror five.MyException error Myerror 32.0 five.MyException at five.CheckingAccount.withdraw(CheckingAccount.java:22) at five.BankDemo.main(BankDemo.java:10) */
Java 提供了一種對象序列化的機制,該機制中,一個對象能夠被表示爲一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。
將序列化對象寫入文件以後,能夠從文件中讀取出來,而且對它進行反序列化,也就是說,對象的類型信息、對象的數據,還有對象中的數據類型能夠用來在內存中新建對象。
整個過程都是 Java 虛擬機(JVM)獨立的,也就是說,在一個平臺上序列化的對象能夠在另外一個徹底不一樣的平臺上反序列化該對象。
類 ObjectInputStream 和 ObjectOutputStream 是高層次的數據流,它們包含序列化和反序列化對象的方法。
ObjectOutputStream 類包含不少寫方法來寫各類數據類型,可是一個特別的方法例外:
public final void writeObject(Object x) throws IOException
上面的方法序列化一個對象,並將它發送到輸出流。類似的 ObjectInputStream 類包含以下反序列化一個對象的方法:
public final Object readObject() throws IOException, ClassNotFoundException
該方法從流中取出下一個對象,並將對象反序列化。它的返回值爲Object,所以,你須要將它轉換成合適的數據類型。
爲了演示序列化在Java中是怎樣工做的,我將使用Employee類,假設咱們定義了以下的Employee類,該類實現了Serializable 接口。
// Employee.java public class Employee implements java.io.Serializable { public String name; public String address; public transient int SSN; public int number; public void mailCheck() { System.out.println("Mailing a check to " + name + " " + address); } }
請注意,一個類的對象要想序列化成功,必須知足兩個條件:
該類必須實現 java.io.Serializable 對象。
該類的全部屬性必須是可序列化的。若是有一個屬性不是可序列化的,則該屬性必須註明是短暫的。
若是你想知道一個 Java 標準類是不是可序列化的,請查看該類的文檔。檢驗一個類的實例是否能序列化十分簡單, 只須要查看該類有沒有實現 java.io.Serializable接口。
ObjectOutputStream 類用來序列化一個對象,以下的 SerializeDemo 例子實例化了一個 Employee 對象,並將該對象序列化到一個文件中。
該程序執行後,就建立了一個名爲 employee.ser 文件。該程序沒有任何輸出,可是你能夠經過代碼研讀來理解程序的做用。
注意: 當序列化一個對象到文件時, 按照 Java 的標準約定是給文件一個 .ser 擴展名。
//SerializeDemo.java package five; import java.io.*; public class SerializeDemo { public static void main(String[] args){ Employee e = new Employee(); e.name = "Nick"; e.address = "Beijing"; e.SSN = 630571017; e.number = 18; try { FileOutputStream fileOut = new FileOutputStream("F:\\java_project\\employee.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(e); out.close(); fileOut.close(); System.out.println("enoloyee.ser"); } catch (Exception e2) { e2.printStackTrace(); } } }
下面的 DeserializeDemo 程序實例了反序列化,/tmp/employee.ser 存儲了 Employee 對象。
//DeserializeDemo.java package five; import java.io.*; public class DeserializeDemo { public static void main(String[] args){ Employee e = null; try { FileInputStream fileIn = new FileInputStream("F:\\java_project\\employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); } catch (IOException i){ i.printStackTrace(); return; } catch (ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; } System.out.println("Employee."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } } /* Employee. Name: Nick Address: Beijing SSN: 0 Number: 18 */
readObject() 方法中的 try/catch代碼塊嘗試捕獲 ClassNotFoundException 異常。對於 JVM 能夠反序列化對象,它必須是可以找到字節碼的類。若是JVM在反序列化對象的過程當中找不到該類,則拋出一個 ClassNotFoundException 異常。
注意,readObject() 方法的返回值被轉化成 Employee 引用。
當對象被序列化時,屬性 SSN 的值爲 630571017,可是由於該屬性是短暫的,該值沒有被髮送到輸出流。因此反序列化後 Employee 對象的 SSN 屬性爲 0。
Java 鏈接 MySQL 須要驅動包,最新版下載地址爲:http://dev.mysql.com/downloads/connector/j/,解壓後獲得jar庫文件,而後在對應的項目中導入該庫文件。
http://jingyan.baidu.com/article/ca41422fc76c4a1eae99ed9f.html
//MySQLDemo.java package six; import java.sql.*; public class MySQLDemo { // JDBC 驅動名及數據庫 URL(注意冒號,少些一個讓我找了10分鐘) static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/test"; // 數據庫的用戶名與密碼,須要根據本身的設置 static final String USER = "root"; static final String PASS = "suoning"; public static void main(String[] args){ Connection conn = null; Statement stmt = null; try{ // 註冊 JDBC 驅動 Class.forName(JDBC_DRIVER); // 打開連接 System.out.println("鏈接數據庫..."); conn = DriverManager.getConnection(DB_URL, USER, PASS); // 執行查詢 System.out.println("實例化Statement..."); stmt = conn.createStatement(); String sql; sql = "SELECT * FROM user"; ResultSet rs = stmt.executeQuery(sql); // 展開結果集數據庫 while (rs.next()){ // 經過字段檢索 int id = rs.getInt("id"); String name = rs.getString("name"); // 輸出數據 System.out.print(id); System.out.print(" "); System.out.print(name); System.out.println(); } // 完成後關閉 rs.close(); stmt.close(); conn.close(); } catch (SQLException e){ // 處理 JDBC 錯誤 e.printStackTrace(); } catch (Exception e){ // 處理 Class.forName 錯誤 e.printStackTrace(); } finally{ // 關閉資源 try{ if(stmt!=null) stmt.close(); } catch (SQLException e){ } try{ if(conn!=null) conn.close(); } catch (SQLException e){ e.printStackTrace(); } } System.out.println("The end."); } } /* 鏈接數據庫... 實例化Statement... 1 nick 2 jenny 3 honey The end. */
網絡編程是指編寫運行在多個設備(計算機)的程序,這些設備都經過網絡鏈接起來。
java.net 包中 J2SE 的 API 包含有類和接口,它們提供低層次的通訊細節。你能夠直接使用這些類和接口,來專一於解決問題,而不用關注通訊細節。
java.net 包中提供了兩種常見的網絡協議的支持:
TCP:TCP 是傳輸控制協議的縮寫,它保障了兩個應用程序之間的可靠通訊。一般用於互聯網協議,被稱 TCP / IP。
UDP:UDP 是用戶數據報協議的縮寫,一個無鏈接的協議。提供了應用程序之間要發送的數據的數據包
套接字使用TCP提供了兩臺計算機之間的通訊機制。 客戶端程序建立一個套接字,並嘗試鏈接服務器的套接字。
當鏈接創建時,服務器會建立一個 Socket 對象。客戶端和服務器如今能夠經過對 Socket 對象的寫入和讀取來進行進行通訊。
java.net.Socket 類表明一個套接字,而且 java.net.ServerSocket 類爲服務器程序提供了一種來監聽客戶端,並與他們創建鏈接的機制。
如下步驟在兩臺計算機之間使用套接字創建TCP鏈接時會出現:
服務器實例化一個 ServerSocket 對象,表示經過服務器上的端口通訊。
服務器調用 ServerSocket 類的 accept() 方法,該方法將一直等待,直到客戶端鏈接到服務器上給定的端口。
服務器正在等待時,一個客戶端實例化一個 Socket 對象,指定服務器名稱和端口號來請求鏈接。
Socket 類的構造函數試圖將客戶端鏈接到指定的服務器和端口號。若是通訊被創建,則在客戶端建立一個 Socket 對象可以與服務器進行通訊。
在服務器端,accept() 方法返回服務器上一個新的 socket 引用,該 socket 鏈接到客戶端的 socket。
鏈接創建後,經過使用 I/O 流在進行通訊,每個socket都有一個輸出流和一個輸入流,客戶端的輸出流鏈接到服務器端的輸入流,而客戶端的輸入流鏈接到服務器端的輸出流。
TCP 是一個雙向的通訊協議,所以數據能夠經過兩個數據流在同一時間發送.如下是一些類提供的一套完整的有用的方法來實現 socket。
服務器應用程序經過使用 java.net.ServerSocket 類以獲取一個端口,而且偵聽客戶端請求。
ServerSocket 類有四個構造方法:
序號 | 方法描述 |
1 | public ServerSocket(int port) throws IOException 建立綁定到特定端口的服務器套接字。 |
2 | public ServerSocket(int port, int backlog) throws IOException 利用指定的 backlog 建立服務器套接字並將其綁定到指定的本地端口號。 |
3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException 使用指定的端口、偵聽 backlog 和要綁定到的本地 IP 地址建立服務器。 |
4 | public ServerSocket() throws IOException 建立非綁定服務器套接字。 |
建立非綁定服務器套接字。 若是 ServerSocket 構造方法沒有拋出異常,就意味着你的應用程序已經成功綁定到指定的端口,而且偵聽客戶端請求。
這裏有一些 ServerSocket 類的經常使用方法:
序號 | 方法描述 |
1 | public int getLocalPort() 返回此套接字在其上偵聽的端口。 |
2 | public Socket accept() throws IOException 偵聽並接受到此套接字的鏈接。 |
3 | public void setSoTimeout(int timeout) 經過指定超時值啓用/禁用 SO_TIMEOUT,以毫秒爲單位。 |
4 | public void bind(SocketAddress host, int backlog) 將 ServerSocket 綁定到特定地址(IP 地址和端口號)。 |
java.net.Socket 類表明客戶端和服務器都用來互相溝通的套接字。客戶端要獲取一個 Socket 對象經過實例化 ,而 服務器得到一個 Socket 對象則經過 accept() 方法的返回值。
Socket 類有五個構造方法.
序號 | 方法描述 |
1 | public Socket(String host, int port) throws UnknownHostException, IOException. 建立一個流套接字並將其鏈接到指定主機上的指定端口號。 |
2 | public Socket(InetAddress host, int port) throws IOException 建立一個流套接字並將其鏈接到指定 IP 地址的指定端口號。 |
3 | public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException. 建立一個套接字並將其鏈接到指定遠程主機上的指定遠程端口。 |
4 | public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException. 建立一個套接字並將其鏈接到指定遠程地址上的指定遠程端口。 |
5 | public Socket() 經過系統默認類型的 SocketImpl 建立未鏈接套接字 |
當 Socket 構造方法返回,並無簡單的實例化了一個 Socket 對象,它實際上會嘗試鏈接到指定的服務器和端口。
下面列出了一些感興趣的方法,注意客戶端和服務器端都有一個 Socket 對象,因此不管客戶端仍是服務端都可以調用這些方法。
序號 | 方法描述 |
1 | public void connect(SocketAddress host, int timeout) throws IOException 將此套接字鏈接到服務器,並指定一個超時值。 |
2 | public InetAddress getInetAddress() 返回套接字鏈接的地址。 |
3 | public int getPort() 返回此套接字鏈接到的遠程端口。 |
4 | public int getLocalPort() 返回此套接字綁定到的本地端口。 |
5 | public SocketAddress getRemoteSocketAddress() 返回此套接字鏈接的端點的地址,若是未鏈接則返回 null。 |
6 | public InputStream getInputStream() throws IOException 返回此套接字的輸入流。 |
7 | public OutputStream getOutputStream() throws IOException 返回此套接字的輸出流。 |
8 | public void close() throws IOException 關閉此套接字。 |
這個類表示互聯網協議(IP)地址。下面列出了 Socket 編程時比較有用的方法:
序號 | 方法描述 |
1 | static InetAddress getByAddress(byte[] addr) 在給定原始 IP 地址的狀況下,返回 InetAddress 對象。 |
2 | static InetAddress getByAddress(String host, byte[] addr) 根據提供的主機名和 IP 地址建立 InetAddress。 |
3 | static InetAddress getByName(String host) 在給定主機名的狀況下肯定主機的 IP 地址。 |
4 | String getHostAddress() 返回 IP 地址字符串(以文本表現形式)。 |
5 | String getHostName() 獲取此 IP 地址的主機名。 |
6 | static InetAddress getLocalHost() 返回本地主機。 |
7 | String toString() 將此 IP 地址轉換爲 String。 |
//GreetingServer.java package seven; import java.net.*; import java.io.*; public class GreetingServer extends Thread { private ServerSocket serverSocket; public GreetingServer(int port) throws IOException{ serverSocket = new ServerSocket(port); serverSocket.setSoTimeout(9999); } public void run(){ while(true){ try{ System.out.println("Wating for you ..." + serverSocket.getLocalPort()); Socket server = serverSocket.accept(); System.out.println("connected " + server.getRemoteSocketAddress()); DataInputStream in = new DataInputStream(server.getInputStream()); System.out.println(in.readUTF()); DataOutputStream out = new DataOutputStream(server.getOutputStream()); out.writeUTF("The end....." + server.getLocalSocketAddress()); server.close(); } catch(SocketTimeoutException e){ System.out.println("Time out error."); break; } catch(IOException e){ e.printStackTrace(); break; } } } public static void main(String[] args){ int port = Integer.parseInt(args[0]); try { Thread t = new GreetingServer(port); t.start(); } catch (IOException e) { e.printStackTrace(); } } }
//GreetingClient.java package seven; import java.net.*; import java.io.*; public class GreetingClient { public static void main(String[] args){ String serverName = args[0]; int port = Integer.parseInt(args[1]); try { System.out.println(serverName + " " + port); Socket client = new Socket(serverName, port); System.out.println(client.getRemoteSocketAddress()); OutputStream outToServer = client.getOutputStream(); DataOutputStream out = new DataOutputStream(outToServer); out.writeUTF("S" + client.getLocalSocketAddress()); InputStream inFormServer = client.getInputStream(); DataInputStream in = new DataInputStream(inFormServer); System.out.println("s" + in.readUTF()); client.close(); } catch (IOException e) { e.printStackTrace(); } } }