JAVA圖文說(shuō)明教程 第8講 Java網(wǎng)絡(luò)編程(一)
發(fā)表時(shí)間:2024-01-17 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]8.1 網(wǎng)絡(luò)編程的基本概念,TCP/IP協(xié)議簡(jiǎn)介 8.1.1 網(wǎng)絡(luò)基礎(chǔ)知識(shí) 計(jì)算機(jī)網(wǎng)絡(luò)形式多樣,內(nèi)容繁雜。網(wǎng)絡(luò)上的計(jì)算機(jī)要互相通信,必須遵循一定的協(xié)議。目前使用最廣泛的網(wǎng)絡(luò)協(xié)議是Internet上所使用的TCP/IP協(xié)議 網(wǎng)絡(luò)編程的目的就是指直接或間接地通過(guò)網(wǎng)絡(luò)協(xié)議與其他計(jì)算機(jī)進(jìn)行通訊...
8.1 網(wǎng)絡(luò)編程的基本概念,TCP/IP協(xié)議簡(jiǎn)介
8.1.1 網(wǎng)絡(luò)基礎(chǔ)知識(shí)
計(jì)算機(jī)網(wǎng)絡(luò)形式多樣,內(nèi)容繁雜。網(wǎng)絡(luò)上的計(jì)算機(jī)要互相通信,必須遵循一定的協(xié)議。目前使用最廣泛的網(wǎng)絡(luò)協(xié)議是Internet上所使用的TCP/IP協(xié)議
網(wǎng)絡(luò)編程的目的就是指直接或間接地通過(guò)網(wǎng)絡(luò)協(xié)議與其他計(jì)算機(jī)進(jìn)行通訊。網(wǎng)絡(luò)編程中有兩個(gè)主要的問(wèn)題,一個(gè)是如何準(zhǔn)確的定位網(wǎng)絡(luò)上一臺(tái)或多臺(tái)主機(jī),另一個(gè)就是找到主機(jī)后如何可靠高效的進(jìn)行數(shù)據(jù)傳輸。在TCP/IP協(xié)議中IP層主要負(fù)責(zé)網(wǎng)絡(luò)主機(jī)的定位,數(shù)據(jù)傳輸?shù)穆酚桑蒊P地址可以唯一地確定Internet上的一臺(tái)主機(jī)。而TCP層則提供面向應(yīng)用的可靠的或非可靠的數(shù)據(jù)傳輸機(jī)制,這是網(wǎng)絡(luò)編程的主要對(duì)象,一般不需要關(guān)心IP層是如何處理數(shù)據(jù)的。
目前較為流行的網(wǎng)絡(luò)編程模型是客戶(hù)機(jī)/服務(wù)器(C/S)結(jié)構(gòu)。即通信雙方一方作為服務(wù)器等待客戶(hù)提出請(qǐng)求并予以響應(yīng)?蛻(hù)則在需要服務(wù)時(shí)向服務(wù)器提出申請(qǐng)。服務(wù)器一般作為守護(hù)進(jìn)程始終運(yùn)行,監(jiān)聽(tīng)網(wǎng)絡(luò)端口,一旦有客戶(hù)請(qǐng)求,就會(huì)啟動(dòng)一個(gè)服務(wù)進(jìn)程來(lái)響應(yīng)該客戶(hù),同時(shí)自己繼續(xù)監(jiān)聽(tīng)服務(wù)端口,使后來(lái)的客戶(hù)也能及時(shí)得到服務(wù)。
8.1.2網(wǎng)絡(luò)基本概念
IP地址:標(biāo)識(shí)計(jì)算機(jī)等網(wǎng)絡(luò)設(shè)備的網(wǎng)絡(luò)地址,由四個(gè)8位的二進(jìn)制數(shù)組成,中間以小數(shù)點(diǎn)分隔。
如:166.111.136.3 , 166.111.52.80
主機(jī)名(hostname):網(wǎng)絡(luò)地址的助記名,按照域名進(jìn)行分級(jí)管理。
如:www.tsinghua.edu.cn
www.fanso.com
端口號(hào)(port number):網(wǎng)絡(luò)通信時(shí)同一機(jī)器上的不同進(jìn)程的標(biāo)識(shí)。
如:80,21,23,25,其中1~1024為系統(tǒng)保留的端口號(hào)
服務(wù)類(lèi)型(service):網(wǎng)絡(luò)的各種服務(wù)。
http, telnet, ftp, smtp
在Internet上IP地址和主機(jī)名是一一對(duì)應(yīng)的,通過(guò)域名解析可以由主機(jī)名得到機(jī)器的IP,由于機(jī)器名更接近自然語(yǔ)言,容易記憶,所以使用比IP地址廣泛,但是對(duì)機(jī)器而言只有IP地址才是有效的標(biāo)識(shí)符。
通常一臺(tái)主機(jī)上總是有很多個(gè)進(jìn)程需要網(wǎng)絡(luò)資源進(jìn)行網(wǎng)絡(luò)通訊。網(wǎng)絡(luò)通訊的對(duì)象準(zhǔn)確的講不是主機(jī),而應(yīng)該是主機(jī)中運(yùn)行的進(jìn)程。這時(shí)候光有主機(jī)名或IP地址來(lái)標(biāo)識(shí)這么多個(gè)進(jìn)程顯然是不夠的。端口號(hào)就是為了在一臺(tái)主機(jī)上提供更多的網(wǎng)絡(luò)資源而采取得一種手段,也是TCP層提供的一種機(jī)制。只有通過(guò)主機(jī)名或IP地址和端口號(hào)的組合才能唯一的確定網(wǎng)絡(luò)通訊中的對(duì)象:進(jìn)程。
服務(wù)類(lèi)型是在TCP層上面的應(yīng)用層的概念。基于TCP/IP協(xié)議可以構(gòu)建出各種復(fù)雜的應(yīng)用,服務(wù)類(lèi)型是那些已經(jīng)被標(biāo)準(zhǔn)化了的應(yīng)用,一般都是服務(wù)器網(wǎng)絡(luò)(軟件)。讀者可以編寫(xiě)自己的基于網(wǎng)絡(luò)的服務(wù)器,但都不能被稱(chēng)作標(biāo)準(zhǔn)的服務(wù)類(lèi)型。
8.1.3兩類(lèi)傳輸協(xié)議:TCP;UDP
盡管TCP/IP協(xié)議的名稱(chēng)中只有TCP這個(gè)協(xié)議名,但是在TCP/IP的傳輸層同時(shí)存在TCP和UDP兩個(gè)協(xié)議。
TCP是Tranfer Control Protocol的簡(jiǎn)稱(chēng),是一種面向連接的保證可靠傳輸?shù)膮f(xié)議。通過(guò)TCP協(xié)議傳輸,得到的是一個(gè)順序的無(wú)差錯(cuò)的數(shù)據(jù)流。發(fā)送方和接收方的成對(duì)的兩個(gè)socket之間必須建立連接,以便在TCP協(xié)議的基礎(chǔ)上進(jìn)行通信,當(dāng)一個(gè)socket(通常都是server socket)等待建立連接時(shí),另一個(gè)socket可以要求進(jìn)行連接,一旦這兩個(gè)socket連接起來(lái),它們就可以進(jìn)行雙向數(shù)據(jù)傳輸,雙方都可以進(jìn)行發(fā)送或接收操作。
UDP是User Datagram Protocol的簡(jiǎn)稱(chēng),是一種無(wú)連接的協(xié)議,每個(gè)數(shù)據(jù)報(bào)都是一個(gè)獨(dú)立的信息,包括完整的源地址或目的地址,它在網(wǎng)絡(luò)上以任何可能的路徑傳往目的地,因此能否到達(dá)目的地,到達(dá)目的地的時(shí)間以及內(nèi)容的正確性都是不能被保證的。
下面我們對(duì)這兩種協(xié)議做簡(jiǎn)單比較:
使用UDP時(shí),每個(gè)數(shù)據(jù)報(bào)中都給出了完整的地址信息,因此無(wú)需要建立發(fā)送方和接收方的連接。對(duì)于TCP協(xié)議,由于它是一個(gè)面向連接的協(xié)議,在socket之間進(jìn)行數(shù)據(jù)傳輸之前必然要建立連接,所以在TCP中多了一個(gè)連接建立的時(shí)間。
使用UDP傳輸數(shù)據(jù)時(shí)是有大小限制的,每個(gè)被傳輸?shù)臄?shù)據(jù)報(bào)必須限定在64KB之內(nèi)。而TCP沒(méi)有這方面的限制,一旦連接建立起來(lái),雙方的socket就可以按統(tǒng)一的格式傳輸大量的數(shù)據(jù)。UDP是一個(gè)不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報(bào)并不一定以相同的次序到達(dá)接收方。而TCP是一個(gè)可靠的協(xié)議,它確保接收方完全正確地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù)。
總之,TCP在網(wǎng)絡(luò)通信上有極強(qiáng)的生命力,例如遠(yuǎn)程連接(Telnet)和文件傳輸(FTP)都需要不定長(zhǎng)度的數(shù)據(jù)被可靠地傳輸。相比之下UDP操作簡(jiǎn)單,而且僅需要較少的監(jiān)護(hù),因此通常用于局域網(wǎng)高可靠性的分散系統(tǒng)中client/server應(yīng)用程序。
讀者可能要問(wèn),既然有了保證可靠傳輸?shù)腡CP協(xié)議,為什么還要非可靠傳輸?shù)腢DP協(xié)議呢?主要的原因有兩個(gè)。一是可靠的傳輸是要付出代價(jià)的,對(duì)數(shù)據(jù)內(nèi)容正確性的檢驗(yàn)必然占用計(jì)算機(jī)的處理時(shí)間和網(wǎng)絡(luò)的帶寬,因此TCP傳輸?shù)男什蝗鏤DP高。二是在許多應(yīng)用中并不需要保證嚴(yán)格的傳輸可靠性,比如視頻會(huì)議系統(tǒng),并不要求音頻視頻數(shù)據(jù)絕對(duì)的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會(huì)更合理一些。
8.2 基于URL的高層次Java網(wǎng)絡(luò)編程
8.2.1一致資源定位器URL
URL(Uniform Resource Locator)是一致資源定位器的簡(jiǎn)稱(chēng),它表示Internet上某一資源的地址。通過(guò)URL我們可以訪(fǎng)問(wèn)Internet上的各種網(wǎng)絡(luò)資源,比如最常見(jiàn)的WWW,F(xiàn)TP站點(diǎn)。瀏覽器通過(guò)解析給定的URL可以在網(wǎng)絡(luò)上查找相應(yīng)的文件或其他資源。
URL是最為直觀的一種網(wǎng)絡(luò)定位方法。使用URL符合人們的語(yǔ)言習(xí)慣,容易記憶,所以應(yīng)用十分廣泛。而且在目前使用最為廣泛的TCP/IP中對(duì)于URL中主機(jī)名的解析也是協(xié)議的一個(gè)標(biāo)準(zhǔn),即所謂的域名解析服務(wù)。使用URL進(jìn)行網(wǎng)絡(luò)編程,不需要對(duì)協(xié)議本身有太多的了解,功能也比較弱,相對(duì)而言是比較簡(jiǎn)單的,所以在這里我們先介紹在Java中如何使用URL進(jìn)行網(wǎng)絡(luò)編程來(lái)引導(dǎo)讀者入門(mén)。
8.2.2 URL的組成
protocol://resourceName
協(xié)議名(protocol)指明獲取資源所使用的傳輸協(xié)議,如http、ftp、gopher、file等,資源名(resourceName)則應(yīng)該是資源的完整地址,包括主機(jī)名、端口號(hào)、文件名或文件內(nèi)部的一個(gè)引用。例如:
http://www.sun.com/ 協(xié)議名://主機(jī)名
http://home.netscape.com/home/welcome.html 協(xié)議名://機(jī)器名+文件名
http://www.gamelan.com:80/Gamelan/network.html#BOTTOM 協(xié)議名://機(jī)器名+端口號(hào)+文件名+內(nèi)部引用
端口號(hào)是和Socket編程相關(guān)的一個(gè)概念,初學(xué)者不必在此深究,在后面會(huì)有詳細(xì)講解。內(nèi)部引用是HTML中的標(biāo)記,有興趣的讀者可以參考有關(guān)HTML的書(shū)籍。
8.2.3 創(chuàng)建一個(gè)URL
為了表示URL, java.net中實(shí)現(xiàn)了類(lèi)URL。我們可以通過(guò)下面的構(gòu)造方法來(lái)初始化一個(gè)URL對(duì)象:
。1) public URL (String spec);
通過(guò)一個(gè)表示URL地址的字符串可以構(gòu)造一個(gè)URL對(duì)象。
URL urlBase=new URL("http://www. 263.net/")
。2) public URL(URL context, String spec);
通過(guò)基URL和相對(duì)URL構(gòu)造一個(gè)URL對(duì)象。
URL net263=new URL ("http://www.263.net/");
URL index263=new URL(net263, "index.html")
。3) public URL(String protocol, String host, String file);
new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");
。4) public URL(String protocol, String host, int port, String file);
URL gamelan=new URL("http", "www.gamelan.com", 80, "Pages/Gamelan.network.html");
注意:類(lèi)URL的構(gòu)造方法都聲明拋棄非運(yùn)行時(shí)例外(MalformedURLException),因此生成URL對(duì)象時(shí),我們必須要對(duì)這一例外進(jìn)行處理,通常是用try-catch語(yǔ)句進(jìn)行捕獲。格式如下:
try{
URL myURL= new URL(…)
}catch (MalformedURLException e){
…
//exception handler code here
…
}
8.2.4 解析一個(gè)URL
一個(gè)URL對(duì)象生成后,其屬性是不能被改變的,但是我們可以通過(guò)類(lèi)URL所提供的方法來(lái)獲取這些屬性:
public String getProtocol() 獲取該URL的協(xié)議名。
public String getHost() 獲取該URL的主機(jī)名。
public int getPort() 獲取該URL的端口號(hào),如果沒(méi)有設(shè)置端口,返回-1。
public String getFile() 獲取該URL的文件名。
public String getRef() 獲取該URL在文件中的相對(duì)位置。
public String getQuery() 獲取該URL的查詢(xún)信息。
public String getPath() 獲取該URL的路徑
public String getAuthority() 獲取該URL的權(quán)限信息
public String getUserInfo() 獲得使用者的信息
public String getRef() 獲得該URL的錨
下面的例子中,我們生成一個(gè)URL對(duì)象,并獲取它的各個(gè)屬性。
import java.net.*;
import java.io.*;
public class ParseURL{
public static void main (String [] args) throws Exception{
URL Aurl=new URL("http://java.sun.com:80/docs/books/");
URL tuto=new URL(Aurl,"tutorial.intro.html#DOWNLOADING");
System.out.println("protocol="+ tuto.getProtocol());
System.out.println("host ="+ tuto.getHost());
System.out.println("filename="+ tuto.getFile());
System.out.println("port="+ tuto.getPort());
System.out.println("ref="+tuto.getRef());
System.out.println("query="+tuto.getQuery());
System.out.println("path="+tuto.getPath());
System.out.println("UserInfo="+tuto.getUserInfo());
System.out.println("Authority="+tuto.getAuthority());
}
}
執(zhí)行結(jié)果為:
protocol=http host =java.sun.com filename=/docs/books/tutorial.intro.html
port=80
ref=DOWNLOADING
query=null
path=/docs/books/tutorial.intro.html
UserInfo=null
Authority=java.sun.com:80
8.2.5 從URL讀取WWW網(wǎng)絡(luò)資源
當(dāng)我們得到一個(gè)URL對(duì)象后,就可以通過(guò)它讀取指定的WWW資源。這時(shí)我們將使用URL的方法openStream(),其定義為:
InputStream openStream();
方法openSteam()與指定的URL建立連接并返回InputStream類(lèi)的對(duì)象以從這一連接中讀取數(shù)據(jù)。
public class URLReader {
public static void main(String[] args) throws Exception {
//聲明拋出所有例外
URL tirc = new URL("http://www.tirc1.cs.tsinghua.edu.cn/");
//構(gòu)建一URL對(duì)象
BufferedReader in = new BufferedReader(new InputStreamReader(tirc.openStream()));
//使用openStream得到一輸入流并由此構(gòu)造一個(gè)BufferedReader對(duì)象
String inputLine;
while ((inputLine = in.readLine()) != null)
//從輸入流不斷的讀數(shù)據(jù),直到讀完為止
System.out.println(inputLine); //把讀入的數(shù)據(jù)打印到屏幕上
in.close(); //關(guān)閉輸入流
}
}
8.2.6 通過(guò)URLConnetction連接WWW
通過(guò)URL的方法openStream(),我們只能從網(wǎng)絡(luò)上讀取數(shù)據(jù),如果我們同時(shí)還想輸出數(shù)據(jù),例如向服務(wù)器端的CGI程序發(fā)送一些數(shù)據(jù),我們必須先與URL建立連接,然后才能對(duì)其進(jìn)行讀寫(xiě),這時(shí)就要用到類(lèi)URLConnection了。CGI是公共網(wǎng)關(guān)接口(Common Gateway Interface)的簡(jiǎn)稱(chēng),它是用戶(hù)瀏覽器和服務(wù)器端的應(yīng)用程序進(jìn)行連接的接口,有關(guān)CGI程序設(shè)計(jì),請(qǐng)讀者參考有關(guān)書(shū)籍。
類(lèi)URLConnection也在包java.net中定義,它表示Java程序和URL在網(wǎng)絡(luò)上的通信連接。當(dāng)與一個(gè)URL建立連接時(shí),首先要在一個(gè)URL對(duì)象上通過(guò)方法openConnection()生成對(duì)應(yīng)的URLConnection對(duì)象。例如下面的程序段首先生成一個(gè)指向地址http://edu.chinaren.com/index.shtml的對(duì)象,然后用openConnection()打開(kāi)該URL對(duì)象上的一個(gè)連接,返回一個(gè)URLConnection對(duì)象。如果連接過(guò)程失敗,將產(chǎn)生IOException.
Try{
URL netchinaren = new URL ("http://edu.chinaren.com/index.shtml");
URLConnectonn tc = netchinaren.openConnection();
}catch(MalformedURLException e){ //創(chuàng)建URL()對(duì)象失敗
…
}catch (IOException e){ //openConnection()失敗
…
}
類(lèi)URLConnection提供了很多方法來(lái)設(shè)置或獲取連接參數(shù),程序設(shè)計(jì)時(shí)最常使用的是getInputStream()和getOurputStream(),其定義為:
InputSteram getInputSteram();
OutputSteram getOutputStream();
通過(guò)返回的輸入/輸出流我們可以與遠(yuǎn)程對(duì)象進(jìn)行通信?聪旅娴睦樱
URL url =new URL ("http://www.javasoft.com/cgi-bin/backwards");
//創(chuàng)建一URL對(duì)象
URLConnectin con=url.openConnection();
//由URL對(duì)象獲取URLConnection對(duì)象
DataInputStream dis=new DataInputStream (con.getInputSteam());
//由URLConnection獲取輸入流,并構(gòu)造DataInputStream對(duì)象
PrintStream ps=new PrintSteam(con.getOutupSteam());
//由URLConnection獲取輸出流,并構(gòu)造PrintStream對(duì)象
String line=dis.readLine(); //從服務(wù)器讀入一行
ps.println("client…"); //向服務(wù)器寫(xiě)出字符串 "client…"
其中backwards為服務(wù)器端的CGI程序。實(shí)際上,類(lèi)URL的方法openSteam()是通過(guò)URLConnection來(lái)實(shí)現(xiàn)的。它等價(jià)于
openConnection().getInputStream();
基于URL的網(wǎng)絡(luò)編程在底層其實(shí)還是基于下面要講的Socket接口的。WWW,F(xiàn)TP等標(biāo)準(zhǔn)化的網(wǎng)絡(luò)服務(wù)都是基于TCP協(xié)議的,所以本質(zhì)上講URL編程也是基于TCP的一種應(yīng)用。