1 TCP Sockets基礎html
Sockets是一個編程抽象概念,它是網絡上與另外一個應用程序通訊鏈接的句柄。Sockets編程將用戶代碼與TCP/IP協議堆棧的底層實現隔離開,容許用戶靈活地實現本身的編程。java
基於TCP協議的TCP Sockets須要四個方面的數據:程序員
(1) 本地系統的IP地址。web
(2) 本地應用程序正在使用的TCP端口號。數據庫
(3) 通訊的遠程系統的IP地址。編程
(4) 通訊的遠程系統響應的TCP端口號。安全
TCP Sockets的應用模型一般是客戶/服務器模型,一個服務器在一個特定端口等待遠程計算機請求資源,給予響應。客戶程序綁定到這個端口,創建一個可靠鏈接來用於通訊。服務器
面向鏈接的操做使用TCP協議,在這個模式下的Socket必須在發送數據以前與目的地的Socket取得一個鏈接。鏈接創建後,Socket就可使用一個流接口:打開—讀—寫—關閉。全部發送網絡
信息都會在另外一端以一樣的順序被接收。面向鏈接的操做比無鏈接的操做效率低,可是數據的安全性更高。因爲Socket使用是雙方的,因此在客戶端和服務器端的使用稍有不一樣。 併發
(1) 客戶端請求Socket的步驟以下:
① 創建客戶端Socket鏈接;
② 獲得Socket的讀和寫的流;
③ 利用流;
④ 關閉流;
⑤ 關閉Socket。
使用一個服務器端的Socket請求比使用一個客戶端Socket請求要麻煩一些。服務器並非主動地創建鏈接。相反地,服務器被動地監聽客戶端的鏈接請示,而後給它們服務。
(2) 服務器端Socket要完成如下的基本的步驟:
① 創建一個服務器Socket並開始監聽;
② 使用accept()方法取得新的鏈接;
③ 創建輸入和輸出流;
④ 在已有的協議上產生會話;
⑤ 關閉客戶端流和Socket;
⑥ 回到②或者轉到⑦;
⑦ 關閉服務器Socket。
1.1 InetAddress類
InetAddress對象表示一個Internet主機地址。這個主機地址能夠經過名字和IP地址來標識。名字即主機名,例如本機名字爲snowing,爲字符串類型;IP地址爲192.100.100.43,爲四字節的數字,書寫形式爲a.b.c.d。InetAddress類的幾個經常使用方法以下:
public static InetAddress getByName(String host) throws UnknownHostException 經過名字能夠獲得主機的IP地址。
public String getHostAddress() 返回IP地址的字符串格式。
public String getHostName() 返回IP地址的主機名。
public static InetAddress getLocalHost() throws UnknownHostException 以InetAddress類封裝的格式返回本機地址。
public String toString() 轉換成字符串格式。
例:InetAddress對象應用的測試。獲取本機地址並轉換成字符串輸出,輸出本地主機名和IP地址。
1 import java.net.*; 2 public class FindHost 3 { 4 public static void main(String[] args) 5 { 6 try 7 { 8 InetAddress h = InetAddress.getLocalHost(); 9 System.out.println("toString():" + h.toString()); 10 System.out.println("getHostName():" +h.getHostName()); 11 System.out.println("getHostAddress():"+h.getHostAddress()); 12 } 13 catch(UnknownHostException e) 14 { 15 System.out.println(e.getMessage()); 16 } 17 } 18 }
1.2 Socket類
Socket是對TCP/IP協議的封裝,Socket自己並非協議,而是一個調用接口(API),經過Socket,咱們才能使用TCP/IP協議。Socket的出現只是使得程序員更方便地使用TCP/IP協議棧而
已,是對TCP/IP協議的抽象,從而造成了咱們知道的一些最基本的函數接口。
Socket類用來實現客戶端的Socket。經常使用的構造方法有如下三種:
public Socket() 建立一個無鏈接的Socket。
public Socket(InetAddress address, int port) 建立流式Socket,將它鏈接到InetdAdress類指明的主機和port端口上。
public Socket(String host, int port) 建立流式Socket並將它鏈接到特定host的特定port端口上。
1.2.1 創建客戶端程序,訪問網址10.167.10.133,返回網址的首頁寫入文件jftt.html。
1. 程序創建的步驟
(1) 創建到 10.167.10.133且端口爲80的Socket鏈接。
Socket clientSocket = new Socket("10.167.10.133", 80);
(2) 初始化字節流。鏈接創建後的數據傳輸經過數據輸入輸出流實現,寫文件又經過文件輸入輸出流來實現。各類流對象的初始化以下:
DataOutputStream outbound = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream inbound = new DataInputStream(clientSocket.getInputStream());
InputStreamReader inS = new InputStreamReader(inbound);
File f = new File("jftt.html");
FileOutputStream fOut = new FileOutputStream(f);
PrintStream p = new PrintStream(fOut);
(3) 發送請求。
outbound.writeBytes("GET / HTTP/1.0\r\n\r\n");
(4) 返回數據後,循環寫入文件。
int c;
while((c = inS.read()) != -1)
p.print((char)c);
(5) 關閉流。
inS.close();
outbound.close();
inbound.close();
clientSocket.close();
1.3 Socket客戶端與服務器端通訊
1.3.1 Socket 客戶端實例
以下的GreetingClient 是一個客戶端程序,該程序經過socket鏈接到服務器併發送一個請求,而後等待一個響應。
package scoket; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class GreetingClient { public static void main(String[] args) { // TODO 自動生成的方法存根 String serverName = args[1]; int port = Integer.parseInt(args[0]); try { System.out.println("Connecting to " + serverName + " on port " + port); Socket client = new Socket(serverName, port); System.out.println("Just connected to " + client.getRemoteSocketAddress()); OutputStream outToServer = client.getOutputStream(); DataOutputStream out = new DataOutputStream(outToServer); out.writeUTF("Hello from " + client.getLocalSocketAddress()); InputStream inFromServer = client.getInputStream(); DataInputStream in = new DataInputStream(inFromServer); System.out.println("Server says " + in.readUTF()); client.close(); }catch(IOException e) { e.printStackTrace(); } } }
1.3.2 Socket 服務端實例
以下的GreetingServer 程序是一個服務器端應用程序,使用Socket來監聽一個指定的端口。
package scoket; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; public class GreetingServer extends Thread{ // TODO 自動生成的方法存根 private ServerSocket serverSocket; public GreetingServer(int port) throws IOException { serverSocket = new ServerSocket(port); serverSocket.setSoTimeout(10000); } public void run() { while(true) { try { System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "..."); Socket server = serverSocket.accept(); System.out.println("Just connected to " + server.getRemoteSocketAddress()); DataInputStream in = new DataInputStream(server.getInputStream()); System.out.println(in.readUTF()); DataOutputStream out = new DataOutputStream(server.getOutputStream()); out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress() + "\nGoodbye!"); server.close(); }catch(SocketTimeoutException s) { System.out.println("Socket timed out!"); 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(); } } }
1.3.3 運行.java
1)首先在調試配置裏配置運行參數args[0]、args[1],即:6066 localhost
2)編譯運行GreetingServer,控制檯輸出:Waiting for client on port 6066...
3)編譯運行GreetingClient,控制檯輸出:Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!
2 網頁顯示控件
2.1 JEditorPane
JEditorPane類是一個文本組件,經過實現相應的EditorKit接口能夠編輯一些特殊格式的內容。它的內容類型有三種:
(1) text/plain:使用默認的DefaultEditorKit的擴展,處理普通文本。
(2) txt/html:使用javax.swing.text.html.HTMLEditorKit提供HTML3.2的幫助,用以處理HTML文本,針對HTML中存在的一些連接,進行點擊時能夠激活超連接事件。
(3) txt/rtf:使用javax.swing.text.rtf.RTFEditorKit實現對RTF格式文本的處理。
這裏側重於處理HTML文本的狀況,JEditorPane類的構造函數和處理HTML經常使用到的方法以下:
public JEditorPane() 構建一個空JeditorPane。
public JEditorPane(String url) 構建一個基於URL聲明的字符串的JEditorPane。
public JEditorPane(URL initialPage) 構建一個基於特定URL對象的JeditorPane。
public void addHyperlinkListener(HyperlinkListener listener) 添加一個超連接監聽者,通知任何變化,例如選中一個連接並進入時。
public void setPage(String url) 設置顯示的URL頁面。 字符串url 表示頁面的URL地址。
public void setPage(URL page) 設置顯示的URL對象表明的page頁面。
public void setText(String t) 設置指定t內容。
public void setEditable(boolean b) b爲true時,可編輯;b爲false時,不可編輯,但只有當b爲false時,才能夠響應超連接事件。
2.2 HyperlinkListener和HyperlinkEvent
HyperlinkListener是超連接事件監聽者接口,繼承於EventListener接口,只有一個事件:超連接更新,當點擊連接或者進入連接時引起。這個事件的方法爲:
public void hyperlinkUpdate(HyperlinkEvent e) 當更新一個超連接時調用此方法。
HyperlinkEvent是超連接事件,用於通知有關超文本連接的變化,它有兩個經常使用方法,一個方法用來得到事件的類型,另外一個方法是得到超連接指向的URL網址。
public HyperlinkEvent.EventType getEventType()
HyperlinkEvent.EventType
HyperlinkEvent.ACTIVATED 激活超連接HyperlinkEvent.ENTERED 進入超連接的文本
HyperlinkEvent.EXITED 退出超連接的文本
public URL getURL() 返回超連接指向的URL地址
例:使用JEditorPane顯示網頁,當單擊其中的連接時可以給予響應。
1. 分析
(1) 建立JEditorPane對象。
JEditorPane jep = new JEditorPane();
(2) 設置可編輯屬性爲false。
jep.setEditable(false);
(3) 添加超連接事件監聽器。
jep.addHyperlinkListener(new LinkFollower(jep));
(4) 顯示網頁。
jep.setPage(str);
(5) 連接更新事件的處理。
public void hyperlinkUpdate(HyperlinkEvent evt)
{
if(evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
jep.setPage(evt.getURL());
}
例:顯示本公司的網頁
package scoket; import java.io.*; import javax.swing.*; import javax.swing.event.*; public class DisplayHtml { //在新窗口顯示網頁 @SuppressWarnings("deprecation") public static void showNetPage(String str) { JEditorPane jep = new JEditorPane(); jep.setEditable(false); jep.addHyperlinkListener(new LinkFollower(jep)); try { jep.setPage(str); } catch(IOException e) { jep.setContentType("text/html"); jep.setText("<html>Could not load "+ str + " </html>"); } JScrollPane jscrollp = new JScrollPane(jep); JFrame f = new JFrame("富士通主頁"); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); f.setContentPane(jscrollp); f.setSize(600, 400); f.show(); } public static void main(String[] args) { String getURL = "http://10.167.10.133/"; showNetPage(getURL); } } class LinkFollower implements HyperlinkListener { private JEditorPane jep; public LinkFollower(JEditorPane jep) { this.jep = jep; } //超連接更新事件的處理 public void hyperlinkUpdate(HyperlinkEvent evt) { //判斷是不是激活事件 if(evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { //顯示新的網址 jep.setPage(evt.getURL()); } catch(Exception e) { System.out.println(e.getMessage()); } } } }
3 URL類
URL類表明統一資源定位符(Uniform Resource Locator),指向WWW上的資源,資源能夠是一個文件或者一個目錄,也能夠是一個更加複雜的對象,如對數據庫的查詢或者搜索引擎的查詢。一般,一個URL能夠被拆分紅幾個部分,例如:
http://192.100.100.43:8080/web/index.html?search="Java "
其中: (1) http用來描述使用的協議爲超文本連接協議。
(2) 192.100.100.43是信息存放的主機IP地址(也能夠是主機名,如www.sohu.com.cn)。
(3) 端口號爲8080,默認都爲80端口。
(4) web/index.html爲HTTP服務器上文件的虛擬路徑。
(5) ?search="Java"爲網頁上表單使用GET方法進行查詢的附加部分,?表示後面跟的是提交的表單的名-值對,格式爲「名=值」。search爲查詢詞的名字,Java爲查詢詞的值,即用戶要查詢的值,提交搜索引擎時能夠有0個到多個這樣的查詢名-值對。
URL類用來定位WWW上的資源,從而進行處理,如讀取網頁等。它的構造函數以及一系列經常使用的方法以下:
public URL(String spec) 從指定的字符串spec建立一個URL對象。
public URL(String protocol, String host, int port, String file) 從指定的protocol協議、host主機、port端口號和file文件名建立一個URL對象。
public URL(String protocol, String host, String file) 從指定的protocol協議、主機名host和文件名file建立一個URL對象。
public Object getContent() 獲得URL的內容。
public String getContentType() 返回網頁內容類型,普通網頁爲「text/html」。
public String getFile() 獲得URL文件名。
public String getHost() 獲得URL的主機名。
public String getPath() 獲得URL的路徑部分。
public int getPort() 獲得URL的端口號。
public String getProtocol() 獲得URL的協議名。
public String getQuery() 獲得URL的查詢部分。
public URLConnection openConnection() 返回一個URLConnection對象,表明到URL遠程對象的鏈接。
public InputStream openStream() 打開到URL的鏈接,返回讀取鏈接的輸入流。
public String toExternalForm() 構建表明URL對象的字符串。
public String toString() 轉換成字符串,覆蓋來自對象的toString()方法。
4 URLEncoder類
URLEncoder類是一個工具類,用於HTML表單的編碼。類只包含一個靜態方法,這個方法將字符串轉換成application/x-www-form-urlencoded MIME格式。該方法以下:
public static String encode(String s, String enc) throws UnsupportedEncodingException
使用指定的enc編碼格式將字符串s轉換爲application/x-www-form-urlencoded格式,得以在網上傳輸。
其中:
(1) s爲要轉換的字符串。
(2) enc是字符編碼格式名稱,包括US-ASCII、ISO-8859-一、UTF-8等。
例:將查詢表單提交的網址和相應的兩個查詢「名-值對」使用「UTF-8」編碼格式進行編碼。
1. 分析
(1) 在程序中定義了一個QueryString類,實現多個名-值對的編碼和鏈接。其中一對名-值對編碼以下:
query = URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8");
(2) 名-值對之間用符號&鏈接。
if(!query.trim().equals(""))
query += "&";
(3) 主函數中對QueryString類的引用。
QueryString q = new QueryString("cdtype","GB");
q.add("word","Java");
2. 源程序
package uRL; import java.net.*; import java.io.*; public class UseEncode { public static void main(String[] args) { String fullURL = "http://bingle.pku.edu.cn/scripts/ftp_search.exe?"; //新建QueryString對象,調用方法 QueryString q = new QueryString("cdtype","GB"); q.add("word","Java"); fullURL += q.toString(); //打印編碼後的字符串 System.out.println("編碼後的字符串:" + fullURL); } } //類:處理請求串,編碼成網頁識別格式 class QueryString { private String query; //構造函數,初始名值對的編碼 public QueryString(Object name, Object value) { try { query = URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8"); } catch(UnsupportedEncodingException e) { System.err.println(e); } } //構造函數 //添加名值對,之間用符號&進行鏈接 public synchronized void add(Object name, Object value) { if(!query.trim().equals(""))//若是字符串爲空,則與""相等 query += "&"; try { query += URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8"); } catch(UnsupportedEncodingException e) { System.err.println(e); } } //返回編碼後的字符串 public String toString() { return query; } //清空 public void clear() { query = ""; } }
5 URLDecoder類
URLDecoder類是URLEncoder類的解碼類。它的構造函數和解碼方法以下:
public URLEncoder()
public static String decode(String s, String enc)
使用編碼格式enc對application/x-www-form-urlencoded字符串s進行解碼。
6 URLConnection類
抽象類URLConnection表明應用程序和URL之間通訊鏈接的類的超類。類的實例能夠用來讀取和寫入URL表明的資源。URLConnection類實現的兩個方法。
openConnection() 處理影響到遠程資源的鏈接參數
connect() 同資源進行交互,查詢頭文件和內容
上述兩個方法的實現步驟以下:
(1) 調用openConnection方法創建鏈接對象。
(2) 操做創建參數和普通請求參數。
(3) 調用connect方法創建到遠程對象的實際鏈接。
(4) 遠程對象可用,頭文件和遠程對象的內容能夠訪問。